summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--devices/src/virtio/wl.rs39
-rw-r--r--gpu_buffer/src/lib.rs18
-rw-r--r--src/linux.rs21
-rw-r--r--vm_control/src/lib.rs67
4 files changed, 104 insertions, 41 deletions
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index a8b2603..6a81bf3 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -59,7 +59,7 @@ use data_model::VolatileMemoryError;
 use sys_util::{Error, Result, EventFd, Scm, SharedMemory, GuestAddress, GuestMemory,
                GuestMemoryError, PollContext, PollToken, FileFlags, pipe};
 
-use vm_control::{VmControlError, VmRequest, VmResponse, MaybeOwnedFd};
+use vm_control::{VmControlError, VmRequest, VmResponse, MaybeOwnedFd, GpuMemoryDesc};
 use super::{VirtioDevice, Queue, DescriptorChain, INTERRUPT_STATUS_USED_RING, TYPE_WL};
 
 const VIRTWL_SEND_MAX_ALLOCS: usize = 28;
@@ -236,7 +236,7 @@ fn encode_vfd_new_dmabuf(desc_mem: VolatileSlice,
                          flags: u32,
                          pfn: u64,
                          size: u32,
-                         stride: u32)
+                         desc: GpuMemoryDesc)
                   -> WlResult<u32> {
     let ctrl_vfd_new_dmabuf = CtrlVfdNewDmabuf {
         hdr: CtrlHeader {
@@ -250,12 +250,12 @@ fn encode_vfd_new_dmabuf(desc_mem: VolatileSlice,
         width: Le32::from(0),
         height: Le32::from(0),
         format: Le32::from(0),
-        stride0: Le32::from(stride),
-        stride1: Le32::from(0),
-        stride2: Le32::from(0),
-        offset0: Le32::from(0),
-        offset1: Le32::from(0),
-        offset2: Le32::from(0),
+        stride0: Le32::from(desc.planes[0].stride),
+        stride1: Le32::from(desc.planes[1].stride),
+        stride2: Le32::from(desc.planes[2].stride),
+        offset0: Le32::from(desc.planes[0].offset),
+        offset1: Le32::from(desc.planes[1].offset),
+        offset2: Le32::from(desc.planes[2].offset),
     };
 
     desc_mem.get_ref(0)?.store(ctrl_vfd_new_dmabuf);
@@ -322,8 +322,8 @@ fn encode_resp(desc_mem: VolatileSlice, resp: WlResp) -> WlResult<u32> {
             flags,
             pfn,
             size,
-            stride,
-        } => encode_vfd_new_dmabuf(desc_mem, id, flags, pfn, size, stride),
+            desc,
+        } => encode_vfd_new_dmabuf(desc_mem, id, flags, pfn, size, desc),
         WlResp::VfdRecv { id, data, vfds } => encode_vfd_recv(desc_mem, id, data, vfds),
         WlResp::VfdHup { id } => encode_vfd_hup(desc_mem, id),
         r => {
@@ -512,7 +512,7 @@ enum WlResp<'a> {
         flags: u32,
         pfn: u64,
         size: u32,
-        stride: u32,
+        desc: GpuMemoryDesc,
     },
     VfdRecv {
         id: u32,
@@ -616,20 +616,21 @@ impl WlVfd {
     }
 
     #[cfg(feature = "wl-dmabuf")]
-    fn dmabuf(vm: VmRequester, width: u32, height: u32, format: u32) -> WlResult<(WlVfd, u32)> {
+    fn dmabuf(vm: VmRequester, width: u32, height: u32, format: u32) ->
+        WlResult<(WlVfd, GpuMemoryDesc)> {
         let allocate_and_register_gpu_memory_response =
             vm.request(VmRequest::AllocateAndRegisterGpuMemory { width: width,
                                                                  height: height,
                                                                  format: format })?;
         match allocate_and_register_gpu_memory_response {
-            VmResponse::AllocateAndRegisterGpuMemory { fd, pfn, slot, stride } => {
+            VmResponse::AllocateAndRegisterGpuMemory { fd, pfn, slot, desc } => {
                 let mut vfd = WlVfd::default();
                 // Duplicate FD for shared memory instance.
                 let raw_fd = unsafe { File::from_raw_fd(dup(fd.as_raw_fd())) };
                 let vfd_shm = SharedMemory::from_raw_fd(raw_fd).map_err(WlError::NewAlloc)?;
                 vfd.guest_shared_memory = Some((vfd_shm.size(), vfd_shm.into()));
                 vfd.slot = Some((slot, pfn, vm));
-                Ok((vfd, stride))
+                Ok((vfd, desc))
             }
             _ => Err(WlError::VmBadResponse),
         }
@@ -930,16 +931,16 @@ impl WlState {
 
         match self.vfds.entry(id) {
             Entry::Vacant(entry) => {
-                let (vfd, stride) = WlVfd::dmabuf(self.vm.clone(),
-                                                  width,
-                                                  height,
-                                                  format)?;
+                let (vfd, desc) = WlVfd::dmabuf(self.vm.clone(),
+                                                width,
+                                                height,
+                                                format)?;
                 let resp = WlResp::VfdNewDmabuf {
                     id: id,
                     flags: 0,
                     pfn: vfd.pfn().unwrap_or_default(),
                     size: vfd.size().unwrap_or_default() as u32,
-                    stride: stride,
+                    desc,
                 };
                 entry.insert(vfd);
                 Ok(resp)
diff --git a/gpu_buffer/src/lib.rs b/gpu_buffer/src/lib.rs
index fb69eeb..449ab53 100644
--- a/gpu_buffer/src/lib.rs
+++ b/gpu_buffer/src/lib.rs
@@ -292,6 +292,24 @@ impl Buffer {
         unsafe { gbm_bo_get_num_planes(self.0) }
     }
 
+    /// Handle as u64 for the given plane.
+    pub fn plane_handle(&self, plane: usize) -> u64 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_plane_handle(self.0, plane).u64 }
+    }
+
+    /// Offset in bytes for the given plane.
+    pub fn plane_offset(&self, plane: usize) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_plane_offset(self.0, plane) }
+    }
+
+    /// Length in bytes of one row for the given plane.
+    pub fn plane_stride(&self, plane: usize) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_plane_stride(self.0, plane) }
+    }
+
     /// Exports a new dmabuf/prime file descriptor for the given plane.
     pub fn export_plane_fd(&self, plane: usize) -> Result<File, i32> {
         // This is always safe to call with a valid gbm_bo pointer.
diff --git a/src/linux.rs b/src/linux.rs
index 8aae432..eb85659 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -31,7 +31,7 @@ use qcow::{self, QcowFile};
 use sys_util::*;
 use sys_util;
 use vhost;
-use vm_control::{VmRequest, GpuMemoryAllocator};
+use vm_control::{VmRequest, GpuMemoryAllocator, GpuMemoryPlaneDesc, GpuMemoryDesc};
 #[cfg(feature = "wl-dmabuf")]
 use gpu_buffer;
 
@@ -558,7 +558,8 @@ struct GpuBufferDevice {
 
 #[cfg(feature = "wl-dmabuf")]
 impl GpuMemoryAllocator for GpuBufferDevice {
-    fn allocate(&self, width: u32, height: u32, format: u32) -> sys_util::Result<(File, u32)> {
+    fn allocate(&self, width: u32, height: u32, format: u32) ->
+        sys_util::Result<(File, GpuMemoryDesc)> {
         let buffer = match self.device.create_buffer(
             width,
             height,
@@ -573,15 +574,23 @@ impl GpuMemoryAllocator for GpuBufferDevice {
             Ok(v) => v,
             Err(_) => return Err(sys_util::Error::new(EINVAL)),
         };
-        // We only support the first plane. Buffers with more planes are not
-        // a problem but additional planes will not be registered for access
-        // from guest.
+        // We only support one FD. Buffers with multiple planes are supported
+        // as long as each plane is associated with the same handle.
         let fd = match buffer.export_plane_fd(0) {
             Ok(v) => v,
             Err(e) => return Err(sys_util::Error::new(e)),
         };
 
-        Ok((fd, buffer.stride()))
+        let mut desc = GpuMemoryDesc::default();
+        for i in 0..buffer.num_planes() {
+            // Use stride and offset for plane if handle matches first plane.
+            if buffer.plane_handle(i) == buffer.plane_handle(0) {
+                desc.planes[i] = GpuMemoryPlaneDesc { stride: buffer.plane_stride(i),
+                                                      offset: buffer.plane_offset(i) }
+            }
+        }
+
+        Ok((fd, desc))
     }
 }
 
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 3837bb4..f13faef 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -130,19 +130,32 @@ fn register_memory(vm: &mut Vm, next_mem_pfn: &mut u64, fd: &AsRawFd, size: usiz
     Ok((pfn, slot))
 }
 
+/// Struct that describes the offset and stride of a plane located in GPU memory.
+#[derive(Clone, Copy, Debug, PartialEq, Default)]
+pub struct GpuMemoryPlaneDesc {
+    pub stride: u32,
+    pub offset: u32,
+}
+
+/// Struct that describes a GPU memory allocation that consists of up to 3 planes.
+#[derive(Clone, Copy, Debug, Default)]
+pub struct GpuMemoryDesc {
+    pub planes: [GpuMemoryPlaneDesc; 3],
+}
+
 /// Trait that needs to be implemented in order to service GPU memory allocation
 /// requests. Implementations are expected to support some set of buffer sizes and
 /// formats but every possible combination is not required.
 pub trait GpuMemoryAllocator {
     /// Allocates GPU memory for a buffer of a specific size and format. The memory
-    /// layout for the returned buffer must be linear. A file handle and the stride
-    /// for the buffer are returned on success.
+    /// layout for the returned buffer must be linear. A file handle and the
+    /// description of the planes for the buffer are returned on success.
     ///
     /// # Arguments
     /// * `width` - Width of buffer.
     /// * `height` - Height of buffer.
     /// * `format` - Fourcc format of buffer.
-    fn allocate(&self, width: u32, height: u32, format: u32) -> Result<(File, u32)>;
+    fn allocate(&self, width: u32, height: u32, format: u32) -> Result<(File, GpuMemoryDesc)>;
 }
 
 impl VmRequest {
@@ -281,7 +294,7 @@ impl VmRequest {
                     Some(v) => v,
                     None => return VmResponse::Err(SysError::new(ENODEV)),
                 };
-                let (mut fd, stride) = match allocator.allocate(width, height, format) {
+                let (mut fd, desc) = match allocator.allocate(width, height, format) {
                     Ok(v) => v,
                     Err(e) => return VmResponse::Err(e),
                 };
@@ -296,7 +309,7 @@ impl VmRequest {
                         fd: MaybeOwnedFd::Owned(fd),
                         pfn,
                         slot,
-                        stride },
+                        desc },
                     Err(e) => VmResponse::Err(e),
                 }
             }
@@ -316,15 +329,15 @@ pub enum VmResponse {
     /// number `pfn` and memory slot number `slot`.
     RegisterMemory { pfn: u64, slot: u32 },
     /// The request to allocate and register GPU memory into guest address space was successfully
-    /// done at page frame number `pfn` and memory slot number `slot` for buffer with `stride`.
-    AllocateAndRegisterGpuMemory { fd: MaybeOwnedFd, pfn: u64, slot: u32, stride: u32 },
+    /// done at page frame number `pfn` and memory slot number `slot` for buffer with `desc`.
+    AllocateAndRegisterGpuMemory { fd: MaybeOwnedFd, pfn: u64, slot: u32, desc: GpuMemoryDesc },
 }
 
 const VM_RESPONSE_TYPE_OK: u32 = 1;
 const VM_RESPONSE_TYPE_ERR: u32 = 2;
 const VM_RESPONSE_TYPE_REGISTER_MEMORY: u32 = 3;
 const VM_RESPONSE_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY: u32 = 4;
-const VM_RESPONSE_SIZE: usize = 24;
+const VM_RESPONSE_SIZE: usize = 48;
 
 #[repr(C)]
 #[derive(Clone, Copy, Default)]
@@ -333,7 +346,12 @@ struct VmResponseStruct {
     errno: Le32,
     pfn: Le64,
     slot: Le32,
-    stride: Le32,
+    stride0: Le32,
+    stride1: Le32,
+    stride2: Le32,
+    offset0: Le32,
+    offset1: Le32,
+    offset2: Le32,
 }
 
 // Safe because it only has data and has no implicit padding.
@@ -370,7 +388,14 @@ impl VmResponse {
                        fd: MaybeOwnedFd::Owned(fd),
                        pfn: resp.pfn.into(),
                        slot: resp.slot.into(),
-                       stride: resp.stride.into()
+                       desc: GpuMemoryDesc {
+                           planes: [ GpuMemoryPlaneDesc { stride: resp.stride0.into(),
+                                                          offset: resp.offset0.into() },
+                                     GpuMemoryPlaneDesc { stride: resp.stride1.into(),
+                                                          offset: resp.offset1.into() },
+                                     GpuMemoryPlaneDesc { stride: resp.stride2.into(),
+                                                          offset: resp.offset2.into() } ],
+                       },
                   })
             }
             _ => Err(VmControlError::InvalidType),
@@ -396,13 +421,18 @@ impl VmResponse {
                 resp.pfn = Le64::from(pfn);
                 resp.slot = Le32::from(slot);
             }
-            &VmResponse::AllocateAndRegisterGpuMemory {ref fd, pfn, slot, stride } => {
+            &VmResponse::AllocateAndRegisterGpuMemory {ref fd, pfn, slot, desc } => {
                 fd_buf[0] = fd.as_raw_fd();
                 fd_len = 1;
                 resp.type_ = Le32::from(VM_RESPONSE_TYPE_ALLOCATE_AND_REGISTER_GPU_MEMORY);
                 resp.pfn = Le64::from(pfn);
                 resp.slot = Le32::from(slot);
-                resp.stride = Le32::from(stride);
+                resp.stride0 = Le32::from(desc.planes[0].stride);
+                resp.stride1 = Le32::from(desc.planes[1].stride);
+                resp.stride2 = Le32::from(desc.planes[2].stride);
+                resp.offset0 = Le32::from(desc.planes[0].offset);
+                resp.offset1 = Le32::from(desc.planes[1].offset);
+                resp.offset2 = Le32::from(desc.planes[2].offset);
             }
         }
         let mut buf = [0; VM_RESPONSE_SIZE];
@@ -625,19 +655,24 @@ mod tests {
         shm.set_size(shm_size as u64).unwrap();
         let memory_pfn = 55;
         let memory_slot = 66;
-        let gpu_stride = 32;
+        let memory_planes = [
+            GpuMemoryPlaneDesc { stride: 32, offset: 84 },
+            GpuMemoryPlaneDesc { stride: 48, offset: 96 },
+            GpuMemoryPlaneDesc { stride: 64, offset: 112 }
+        ];
         let r1 = VmResponse::AllocateAndRegisterGpuMemory {
             fd: MaybeOwnedFd::Borrowed(shm.as_raw_fd()),
             pfn: memory_pfn,
             slot: memory_slot,
-            stride: gpu_stride };
+            desc: GpuMemoryDesc { planes: memory_planes },
+        };
         r1.send(&mut scm, &s1).unwrap();
         match VmResponse::recv(&mut scm, &s2).unwrap() {
-            VmResponse::AllocateAndRegisterGpuMemory { fd, pfn, slot, stride } => {
+            VmResponse::AllocateAndRegisterGpuMemory { fd, pfn, slot, desc } => {
                 assert!(fd.as_raw_fd() >= 0);
                 assert_eq!(pfn, memory_pfn);
                 assert_eq!(slot, memory_slot);
-                assert_eq!(stride, gpu_stride);
+                assert_eq!(desc.planes, memory_planes);
             }
             _ => panic!("recv wrong response variant"),
         }