From c5899296c41f9c3991542350a3e2e6118e1972c2 Mon Sep 17 00:00:00 2001 From: Zach Reizner Date: Wed, 5 Sep 2018 10:23:46 -0700 Subject: [PATCH] devices: gpu: add plane info response support In order to properly send dmabufs over the wayland protocol, accurate buffer metadata is needed in the guest. This change plumbs information from minigbm allocations to the guest using a virtio-gpu response. BUG=875998 TEST=wayland-simple-egl Change-Id: I5c80d539bc7757c302ad7adf56f5d3b011304617 Reviewed-on: https://chromium-review.googlesource.com/1227054 Commit-Ready: Zach Reizner Tested-by: Zach Reizner Reviewed-by: David Riley --- devices/src/virtio/gpu/backend.rs | 18 +++++-- devices/src/virtio/gpu/protocol.rs | 76 +++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/devices/src/virtio/gpu/backend.rs b/devices/src/virtio/gpu/backend.rs index 139fd43bd5..b8f98e4d02 100644 --- a/devices/src/virtio/gpu/backend.rs +++ b/devices/src/virtio/gpu/backend.rs @@ -24,8 +24,9 @@ use super::gpu_renderer::{ }; use super::super::resource_bridge::*; -use super::protocol::GpuResponse; -use super::protocol::{VIRTIO_GPU_CAPSET_VIRGL, VIRTIO_GPU_CAPSET_VIRGL2}; +use super::protocol::{ + GpuResponse, GpuResponsePlaneInfo, VIRTIO_GPU_CAPSET_VIRGL, VIRTIO_GPU_CAPSET_VIRGL2, +}; const DEFAULT_WIDTH: u32 = 1280; const DEFAULT_HEIGHT: u32 = 1024; @@ -798,10 +799,21 @@ impl Backend { let res = self.renderer.import_resource(create_args, &image); match res { Ok(res) => { + let format_modifier = buffer.format_modifier(); + let mut plane_info = Vec::with_capacity(buffer.num_planes()); + for plane_index in 0..buffer.num_planes() { + plane_info.push(GpuResponsePlaneInfo { + stride: buffer.plane_stride(plane_index), + offset: buffer.plane_offset(plane_index), + }); + } let mut backed = BackedBuffer::new_renderer_registered(buffer, res, image); slot.insert(Box::new(backed)); - GpuResponse::OkNoData + GpuResponse::OkResourcePlaneInfo { + format_modifier, + plane_info, + } } Err(e) => { error!("failed to import renderer resource: {}", e); diff --git a/devices/src/virtio/gpu/protocol.rs b/devices/src/virtio/gpu/protocol.rs index f3e53a89a8..8ed6b027b8 100644 --- a/devices/src/virtio/gpu/protocol.rs +++ b/devices/src/virtio/gpu/protocol.rs @@ -44,6 +44,7 @@ pub const VIRTIO_GPU_RESP_OK_NODATA: u32 = 0x1100; pub const VIRTIO_GPU_RESP_OK_DISPLAY_INFO: u32 = 0x1101; pub const VIRTIO_GPU_RESP_OK_CAPSET_INFO: u32 = 0x1102; pub const VIRTIO_GPU_RESP_OK_CAPSET: u32 = 0x1103; +pub const VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO: u32 = 0x1104; /* error responses */ pub const VIRTIO_GPU_RESP_ERR_UNSPEC: u32 = 0x1200; @@ -79,6 +80,7 @@ pub fn virtio_gpu_cmd_str(cmd: u32) -> &'static str { VIRTIO_GPU_RESP_OK_DISPLAY_INFO => "VIRTIO_GPU_RESP_OK_DISPLAY_INFO", VIRTIO_GPU_RESP_OK_CAPSET_INFO => "VIRTIO_GPU_RESP_OK_CAPSET_INFO", VIRTIO_GPU_RESP_OK_CAPSET => "VIRTIO_GPU_RESP_OK_CAPSET", + VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO => "VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO", VIRTIO_GPU_RESP_ERR_UNSPEC => "VIRTIO_GPU_RESP_ERR_UNSPEC", VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY => "VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY", VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID => "VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID", @@ -417,6 +419,22 @@ pub struct virtio_gpu_resp_capset { unsafe impl DataInit for virtio_gpu_resp_capset {} +/* VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO */ +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct virtio_gpu_resp_resource_plane_info { + pub hdr: virtio_gpu_ctrl_hdr, + pub count: Le32, + pub padding: Le32, + pub format_modifier: Le64, + pub strides: [Le32; 4], + pub offsets: [Le32; 4], +} + +unsafe impl DataInit for virtio_gpu_resp_resource_plane_info {} + +const PLANE_INFO_MAX_COUNT: usize = 4; + pub const VIRTIO_GPU_EVENT_DISPLAY: u32 = 1 << 0; #[derive(Copy, Clone, Debug)] @@ -567,13 +585,27 @@ impl GpuCommand { } } +#[derive(Debug, PartialEq)] +pub struct GpuResponsePlaneInfo { + pub stride: u32, + pub offset: u32, +} + /// A response to a `GpuCommand`. These correspond to `VIRTIO_GPU_RESP_*`. #[derive(Debug, PartialEq)] pub enum GpuResponse { OkNoData, OkDisplayInfo(Vec<(u32, u32)>), - OkCapsetInfo { id: u32, version: u32, size: u32 }, + OkCapsetInfo { + id: u32, + version: u32, + size: u32, + }, OkCapset(Vec), + OkResourcePlaneInfo { + format_modifier: u64, + plane_info: Vec, + }, ErrUnspec, ErrOutOfMemory, ErrInvalidScanoutId, @@ -589,6 +621,8 @@ pub enum GpuResponseEncodeError { Memory(VolatileMemoryError), /// More displays than are valid were in a `OkDisplayInfo`. TooManyDisplays(usize), + /// More planes than are valid were in a `OkResourcePlaneInfo`. + TooManyPlanes(usize), } impl From for GpuResponseEncodeError { @@ -647,6 +681,44 @@ impl GpuResponse { resp_data_slice.copy_from(data); size_of_val(&hdr) + data.len() } + GpuResponse::OkResourcePlaneInfo { + format_modifier, + ref plane_info, + } => { + if plane_info.len() > PLANE_INFO_MAX_COUNT { + return Err(GpuResponseEncodeError::TooManyPlanes(plane_info.len())); + } + let mut strides = [Le32::default(); PLANE_INFO_MAX_COUNT]; + let mut offsets = [Le32::default(); PLANE_INFO_MAX_COUNT]; + for (plane_index, plane) in plane_info.iter().enumerate() { + strides[plane_index] = plane.stride.into(); + offsets[plane_index] = plane.offset.into(); + } + let plane_info = virtio_gpu_resp_resource_plane_info { + hdr, + count: Le32::from(plane_info.len() as u32), + padding: 0.into(), + format_modifier: format_modifier.into(), + strides, + offsets, + }; + match resp.get_ref(0) { + Ok(resp_ref) => { + resp_ref.store(plane_info); + size_of_val(&plane_info) + } + _ => { + // In case there is too little room in the response slice to store the + // entire virtio_gpu_resp_resource_plane_info, convert response to a regular + // VIRTIO_GPU_RESP_OK_NODATA and attempt to return that. + resp.get_ref(0)?.store(virtio_gpu_ctrl_hdr { + type_: Le32::from(VIRTIO_GPU_RESP_OK_NODATA), + ..hdr + }); + size_of_val(&hdr) + } + } + } _ => { resp.get_ref(0)?.store(hdr); size_of_val(&hdr) @@ -662,6 +734,7 @@ impl GpuResponse { GpuResponse::OkDisplayInfo(_) => VIRTIO_GPU_RESP_OK_DISPLAY_INFO, GpuResponse::OkCapsetInfo { .. } => VIRTIO_GPU_RESP_OK_CAPSET_INFO, GpuResponse::OkCapset(_) => VIRTIO_GPU_RESP_OK_CAPSET, + GpuResponse::OkResourcePlaneInfo { .. } => VIRTIO_GPU_RESP_OK_RESOURCE_PLANE_INFO, GpuResponse::ErrUnspec => VIRTIO_GPU_RESP_ERR_UNSPEC, GpuResponse::ErrOutOfMemory => VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY, GpuResponse::ErrInvalidScanoutId => VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID, @@ -678,6 +751,7 @@ impl GpuResponse { GpuResponse::OkDisplayInfo(_) => true, GpuResponse::OkCapsetInfo { .. } => true, GpuResponse::OkCapset(_) => true, + GpuResponse::OkResourcePlaneInfo { .. } => true, _ => false, } }