blob: a44d3c8755d6e4b553b16346bf5172ce22c14e27 [file] [log] [blame]
// 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::fmt::Debug;
use std::fs::File;
#[cfg(feature = "wl-dmabuf")]
use libc::EINVAL;
#[cfg(feature = "wl-dmabuf")]
use gpu_buffer;
use msg_socket::MsgOnSocket;
use sys_util;
#[allow(dead_code)]
#[derive(Debug, Eq, PartialEq)]
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, MsgOnSocket)]
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, MsgOnSocket)]
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: Debug {
/// 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 std::fmt::Debug for GpuBufferDevice {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "GpuBufferDevice {{opaque}}")
}
}
#[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<dyn GpuMemoryAllocator>>, GpuAllocatorError> {
Ok(None)
}