From 228e4a6a91ea2972b2443d3959c14d862a23c358 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Thu, 7 Jun 2018 15:42:41 -0700 Subject: 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 Reviewed-on: https://chromium-review.googlesource.com/1099856 --- resources/src/gpu_allocator.rs | 106 ++++++++++++++++++++++++++++++++++++++ resources/src/lib.rs | 5 ++ resources/src/system_allocator.rs | 19 ++++++- 3 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 resources/src/gpu_allocator.rs (limited to 'resources/src') 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>, 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>, 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, device_address_space: AddressAllocator, mmio_address_space: AddressAllocator, + gpu_allocator: Option>, 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, io_size: Option, dev_base: u64, dev_size: u64, mmio_base: u64, mmio_size: u64, + create_gpu_allocator: bool, first_irq: u32) -> Option { 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 { 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 { + pub fn create_allocator(&self, first_irq: u32, + gpu_allocation: bool) -> Option { SystemAllocator::new(self.io_base, self.io_size, self.device_base?, self.device_size?, self.mmio_base?, self.mmio_size?, + gpu_allocation, first_irq) } } -- cgit 1.4.1