summary refs log tree commit diff
path: root/resources
diff options
context:
space:
mode:
authorDylan Reid <dgreid@chromium.org>2018-06-07 15:42:41 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-07-09 17:59:23 -0700
commit228e4a6a91ea2972b2443d3959c14d862a23c358 (patch)
tree4b7fd7bf8249b7dde2fbd8b958d836bc0a12d420 /resources
parent20d71f8928e1e95f6554c87cfca12f24f9f652cf (diff)
downloadcrosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.gz
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.bz2
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.lz
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.xz
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.tar.zst
crosvm-228e4a6a91ea2972b2443d3959c14d862a23c358.zip
Move gpu allocator to resources
Combine GPU buffer allocation with the system resource allocator making
life easier as only one allocator needs to get passed to the execute
function.

Change-Id: I199eb0fd6b99b629aaec1ae3295e8a1942da5309
Signed-off-by: Dylan Reid <dgreid@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/1099856
Diffstat (limited to 'resources')
-rw-r--r--resources/Cargo.toml5
-rw-r--r--resources/src/gpu_allocator.rs106
-rw-r--r--resources/src/lib.rs5
-rw-r--r--resources/src/system_allocator.rs19
4 files changed, 133 insertions, 2 deletions
diff --git a/resources/Cargo.toml b/resources/Cargo.toml
index 2569f9d..29fc38a 100644
--- a/resources/Cargo.toml
+++ b/resources/Cargo.toml
@@ -3,6 +3,11 @@ name = "resources"
 version = "0.1.0"
 authors = ["The Chromium OS Authors"]
 
+[features]
+wl-dmabuf = ["gpu_buffer"]
+
 [dependencies]
 data_model = { path = "../data_model" }
+gpu_buffer = { path = "../gpu_buffer", optional = true }
+libc = "*"
 sys_util = { path = "../sys_util" }
diff --git a/resources/src/gpu_allocator.rs b/resources/src/gpu_allocator.rs
new file mode 100644
index 0000000..ea38ba4
--- /dev/null
+++ b/resources/src/gpu_allocator.rs
@@ -0,0 +1,106 @@
+// Copyright 2018 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 std::fs::File;
+
+#[cfg(feature = "wl-dmabuf")]
+use libc::EINVAL;
+
+#[cfg(feature = "wl-dmabuf")]
+use gpu_buffer;
+use sys_util;
+
+#[derive(Debug)]
+pub enum GpuAllocatorError {
+    OpenGpuBufferDevice,
+    CreateGpuBufferDevice,
+}
+
+/// 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
+    /// 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)
+        -> sys_util::Result<(File, GpuMemoryDesc)>;
+}
+
+#[cfg(feature = "wl-dmabuf")]
+pub struct GpuBufferDevice {
+    device: gpu_buffer::Device,
+}
+
+#[cfg(feature = "wl-dmabuf")]
+impl GpuMemoryAllocator for GpuBufferDevice {
+    fn allocate(&self, width: u32, height: u32, format: u32) ->
+        sys_util::Result<(File, GpuMemoryDesc)>
+    {
+        let buffer = match self.device.create_buffer(
+            width,
+            height,
+            gpu_buffer::Format::from(format),
+            // Linear layout is a requirement as virtio wayland guest expects
+            // this for CPU access to the buffer. Scanout and texturing are
+            // optional as the consumer (wayland compositor) is expected to
+            // fall-back to a less efficient meachnisms for presentation if
+            // neccesary. In practice, linear buffers for commonly used formats
+            // will also support scanout and texturing.
+            gpu_buffer::Flags::empty().use_linear(true)) {
+            Ok(v) => v,
+            Err(_) => return Err(sys_util::Error::new(EINVAL)),
+        };
+        // 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)),
+        };
+
+        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))
+    }
+}
+
+#[cfg(feature = "wl-dmabuf")]
+pub fn create_gpu_memory_allocator() -> Result<Option<Box<GpuMemoryAllocator>>, GpuAllocatorError> {
+    let undesired: &[&str] = &["vgem", "pvr"];
+    let fd = gpu_buffer::rendernode::open_device(undesired)
+        .map_err(|_| GpuAllocatorError::OpenGpuBufferDevice)?;
+    let device = gpu_buffer::Device::new(fd)
+        .map_err(|_| GpuAllocatorError::CreateGpuBufferDevice)?;
+    Ok(Some(Box::new(GpuBufferDevice { device })))
+}
+
+#[cfg(not(feature = "wl-dmabuf"))]
+pub fn create_gpu_memory_allocator() -> Result<Option<Box<GpuMemoryAllocator>>, GpuAllocatorError> {
+    Ok(None)
+}
diff --git a/resources/src/lib.rs b/resources/src/lib.rs
index 11cc905..5d12cfc 100644
--- a/resources/src/lib.rs
+++ b/resources/src/lib.rs
@@ -4,10 +4,15 @@
 
 //! Manages system resources that can be allocated to VMs and their devices.
 
+#[cfg(feature = "wl-dmabuf")]
+extern crate gpu_buffer;
+extern crate libc;
 extern crate sys_util;
 
 mod address_allocator;
+mod gpu_allocator;
 mod system_allocator;
 
 pub use address_allocator::AddressAllocator;
+pub use gpu_allocator::{GpuMemoryAllocator, GpuMemoryDesc, GpuMemoryPlaneDesc};
 pub use system_allocator::{AddressRanges, SystemAllocator};
diff --git a/resources/src/system_allocator.rs b/resources/src/system_allocator.rs
index fec8b41..7c406c9 100644
--- a/resources/src/system_allocator.rs
+++ b/resources/src/system_allocator.rs
@@ -3,6 +3,7 @@
 // found in the LICENSE file.
 
 use address_allocator::AddressAllocator;
+use gpu_allocator::{self, GpuMemoryAllocator};
 use sys_util::pagesize;
 
 /// Manages allocating system resources such as address space and interrupt numbers.
@@ -21,11 +22,11 @@ use sys_util::pagesize;
 ///       assert_eq!(a.allocate_device_addresses(0x100), Some(0x10000000));
 ///   }
 /// ```
-#[derive(Debug, Eq, PartialEq)]
 pub struct SystemAllocator {
     io_address_space: Option<AddressAllocator>,
     device_address_space: AddressAllocator,
     mmio_address_space: AddressAllocator,
+    gpu_allocator: Option<Box<GpuMemoryAllocator>>,
     next_irq: u32,
 }
 
@@ -40,10 +41,12 @@ impl SystemAllocator {
     /// * `dev_size` - The size of device memory.
     /// * `mmio_base` - The starting address of MMIO space.
     /// * `mmio_size` - The size of MMIO space.
+    /// * `create_gpu_allocator` - If true, enable gpu memory allocation.
     /// * `first_irq` - The first irq number to give out.
     fn new(io_base: Option<u64>, io_size: Option<u64>,
            dev_base: u64, dev_size: u64,
            mmio_base: u64, mmio_size: u64,
+           create_gpu_allocator: bool,
            first_irq: u32) -> Option<Self> {
         let page_size = pagesize() as u64;
         Some(SystemAllocator {
@@ -54,6 +57,11 @@ impl SystemAllocator {
             },
             device_address_space: AddressAllocator::new(dev_base, dev_size, Some(page_size))?,
             mmio_address_space: AddressAllocator::new(mmio_base, mmio_size, Some(page_size))?,
+            gpu_allocator: if create_gpu_allocator {
+                gpu_allocator::create_gpu_memory_allocator().ok()?
+            } else {
+                None
+            },
             next_irq: first_irq,
         })
     }
@@ -82,6 +90,11 @@ impl SystemAllocator {
     pub fn allocate_mmio_addresses(&mut self, size: u64) -> Option<u64> {
         self.mmio_address_space.allocate(size)
     }
+
+    /// Gets an allocator to be used for GPU memory.
+    pub fn gpu_memory_allocator(&self) -> Option<&GpuMemoryAllocator> {
+        self.gpu_allocator.as_ref().map(|v| v.as_ref())
+    }
 }
 
 /// Used to build a system address map for use in creating a `SystemAllocator`.
@@ -124,10 +137,12 @@ impl AddressRanges {
         self
     }
 
-    pub fn create_allocator(&self, first_irq: u32) -> Option<SystemAllocator> {
+    pub fn create_allocator(&self, first_irq: u32,
+                            gpu_allocation: bool) -> Option<SystemAllocator> {
         SystemAllocator::new(self.io_base, self.io_size,
                              self.device_base?, self.device_size?,
                              self.mmio_base?, self.mmio_size?,
+                             gpu_allocation,
                              first_irq)
     }
 }