mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-25 05:03:05 +00:00
gpu_buffer: create bindings to minigbm
These bindings are needed to allocate dmabufs that will be used for accelerated rendering and zero-copy virtio-wayland support. TEST=cargo test -p gpu_buffer BUG=chromium:837073 Change-Id: I96d7bcdeaa1eda616a25fdcfedcbb734cd585ae7 Reviewed-on: https://chromium-review.googlesource.com/1029410 Commit-Ready: David Reveman <reveman@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org> Reviewed-by: Dylan Reid <dgreid@chromium.org>
This commit is contained in:
parent
e0823392f4
commit
6f6854312d
5 changed files with 778 additions and 0 deletions
8
Cargo.lock
generated
8
Cargo.lock
generated
|
@ -52,6 +52,7 @@ dependencies = [
|
|||
"data_model 0.1.0",
|
||||
"device_manager 0.1.0",
|
||||
"devices 0.1.0",
|
||||
"gpu_buffer 0.1.0",
|
||||
"io_jail 0.1.0",
|
||||
"kernel_cmdline 0.1.0",
|
||||
"kernel_loader 0.1.0",
|
||||
|
@ -133,6 +134,13 @@ name = "gcc"
|
|||
version = "0.3.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "gpu_buffer"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"data_model 0.1.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io_jail"
|
||||
version = "0.1.0"
|
||||
|
|
|
@ -16,6 +16,7 @@ plugin = ["plugin_proto", "crosvm_plugin", "protobuf"]
|
|||
arch = { path = "arch" }
|
||||
devices = { path = "devices" }
|
||||
device_manager = { path = "device_manager" }
|
||||
gpu_buffer = { path = "gpu_buffer", optional = true }
|
||||
io_jail = { path = "io_jail" }
|
||||
kvm = { path = "kvm" }
|
||||
kvm_sys = { path = "kvm_sys" }
|
||||
|
|
7
gpu_buffer/Cargo.toml
Normal file
7
gpu_buffer/Cargo.toml
Normal file
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "gpu_buffer"
|
||||
version = "0.1.0"
|
||||
authors = ["The Chromium OS Authors"]
|
||||
|
||||
[dependencies]
|
||||
data_model = { path = "../data_model" }
|
553
gpu_buffer/src/lib.rs
Normal file
553
gpu_buffer/src/lib.rs
Normal file
|
@ -0,0 +1,553 @@
|
|||
// 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.
|
||||
|
||||
//! A crate for creating [DRM](https://en.wikipedia.org/wiki/Direct_Rendering_Manager) managed
|
||||
//! buffer objects. Such objects are useful for exporting as DMABUFs/prime FDs, texturing, render
|
||||
//! targets, memory mapping, and scanout.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```rust
|
||||
//! # use std::error::Error;
|
||||
//! # use std::fs::File;
|
||||
//! # use std::result::Result;
|
||||
//! # use gpu_buffer::*;
|
||||
//! # fn test() -> Result<(), Box<Error>> {
|
||||
//! let drm_card = File::open("/dev/dri/card0")?;
|
||||
//! let device = Device::new(drm_card).map_err(|_| "failed to create device")?;
|
||||
//! let bo = device
|
||||
//! .create_buffer(1024,
|
||||
//! 512,
|
||||
//! Format::new(b'X', b'R', b'2', b'4'),
|
||||
//! Flags::empty().use_scanout(true))
|
||||
//! .map_err(|_| "failed to create buffer")?;
|
||||
//! assert_eq!(bo.width(), 1024);
|
||||
//! assert_eq!(bo.height(), 512);
|
||||
//! assert_eq!(bo.format(), Format::new(b'X', b'R', b'2', b'4'));
|
||||
//! assert_eq!(bo.num_planes(), 1);
|
||||
//! # Ok(())
|
||||
//! # }
|
||||
//! ```
|
||||
|
||||
extern crate data_model;
|
||||
|
||||
mod raw;
|
||||
|
||||
use std::os::raw::c_void;
|
||||
use std::fmt;
|
||||
use std::cmp::min;
|
||||
use std::fs::File;
|
||||
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::ptr::{copy_nonoverlapping, null_mut};
|
||||
use std::rc::Rc;
|
||||
use std::result::Result;
|
||||
|
||||
use data_model::VolatileSlice;
|
||||
|
||||
use raw::*;
|
||||
|
||||
const MAP_FAILED: *mut c_void = (-1isize as *mut _);
|
||||
|
||||
/// A [fourcc](https://en.wikipedia.org/wiki/FourCC) format identifier.
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct Format(u32);
|
||||
|
||||
impl Format {
|
||||
/// Constructs a format identifer using a fourcc byte sequence.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use gpu_buffer::Format;
|
||||
///
|
||||
/// let format = Format::new(b'X', b'R', b'2', b'4');
|
||||
/// println!("format: {:?}", format);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn new(a: u8, b: u8, c: u8, d: u8) -> Format {
|
||||
Format(a as u32 | (b as u32) << 8 | (c as u32) << 16 | (d as u32) << 24)
|
||||
}
|
||||
|
||||
/// Returns the fourcc code as a sequence of bytes.
|
||||
#[inline(always)]
|
||||
pub fn to_bytes(&self) -> [u8; 4] {
|
||||
let f = self.0;
|
||||
[f as u8, (f >> 8) as u8, (f >> 16) as u8, (f >> 24) as u8]
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for Format {
|
||||
fn from(u: u32) -> Format {
|
||||
Format(u)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Format> for u32 {
|
||||
fn from(f: Format) -> u32 {
|
||||
f.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Format {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let b = self.to_bytes();
|
||||
if b.iter().all(u8::is_ascii_graphic) {
|
||||
write!(f,
|
||||
"fourcc({}{}{}{})",
|
||||
b[0] as char,
|
||||
b[1] as char,
|
||||
b[2] as char,
|
||||
b[3] as char)
|
||||
} else {
|
||||
write!(f,
|
||||
"fourcc(0x{:02x}{:02x}{:02x}{:02x})",
|
||||
b[0],
|
||||
b[1],
|
||||
b[2],
|
||||
b[3])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Usage flags for constructing a buffer object.
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub struct Flags(u32);
|
||||
|
||||
impl Flags {
|
||||
/// Returns empty set of flags.
|
||||
#[inline(always)]
|
||||
pub fn empty() -> Flags {
|
||||
Flags(0)
|
||||
}
|
||||
|
||||
/// Returns the given set of raw `GBM_BO` flags wrapped in a `Flags` struct.
|
||||
#[inline(always)]
|
||||
pub fn new(raw: u32) -> Flags {
|
||||
Flags(raw)
|
||||
}
|
||||
|
||||
/// Sets the scanout flag's presence
|
||||
#[inline(always)]
|
||||
pub fn use_scanout(self, e: bool) -> Flags {
|
||||
if e {
|
||||
Flags(self.0 | GBM_BO_USE_SCANOUT)
|
||||
} else {
|
||||
Flags(self.0 & !GBM_BO_USE_SCANOUT)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the cursor flag's presence
|
||||
#[inline(always)]
|
||||
pub fn use_cursor(self, e: bool) -> Flags {
|
||||
if e {
|
||||
Flags(self.0 | GBM_BO_USE_CURSOR)
|
||||
} else {
|
||||
Flags(self.0 & !GBM_BO_USE_CURSOR)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the cursor 64x64 flag's presence
|
||||
#[inline(always)]
|
||||
pub fn use_cursor64(self, e: bool) -> Flags {
|
||||
if e {
|
||||
Flags(self.0 | GBM_BO_USE_CURSOR_64X64)
|
||||
} else {
|
||||
Flags(self.0 & !GBM_BO_USE_CURSOR_64X64)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the rendering flag's presence
|
||||
#[inline(always)]
|
||||
pub fn use_rendering(self, e: bool) -> Flags {
|
||||
if e {
|
||||
Flags(self.0 | GBM_BO_USE_RENDERING)
|
||||
} else {
|
||||
Flags(self.0 & !GBM_BO_USE_RENDERING)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the linear flag's presence
|
||||
#[inline(always)]
|
||||
pub fn use_linear(self, e: bool) -> Flags {
|
||||
if e {
|
||||
Flags(self.0 | GBM_BO_USE_LINEAR)
|
||||
} else {
|
||||
Flags(self.0 & !GBM_BO_USE_LINEAR)
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the texturing flag's presence
|
||||
#[inline(always)]
|
||||
pub fn use_texturing(self, e: bool) -> Flags {
|
||||
if e {
|
||||
Flags(self.0 | GBM_BO_USE_TEXTURING)
|
||||
} else {
|
||||
Flags(self.0 & !GBM_BO_USE_TEXTURING)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct DeviceInner {
|
||||
_fd: File,
|
||||
gbm: *mut gbm_device,
|
||||
}
|
||||
|
||||
impl Drop for DeviceInner {
|
||||
fn drop(self: &mut DeviceInner) {
|
||||
// Safe because DeviceInner is only constructed with a valid gbm_device.
|
||||
unsafe {
|
||||
gbm_device_destroy(self.gbm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A device capable of allocating `Buffer`.
|
||||
#[derive(Clone)]
|
||||
pub struct Device(Rc<DeviceInner>);
|
||||
|
||||
impl Device {
|
||||
/// Returns a new `Device` using the given `fd` opened from a device in `/dev/dri/`.
|
||||
pub fn new(fd: File) -> Result<Device, ()> {
|
||||
// gbm_create_device is safe to call with a valid fd, and we check that a valid one is
|
||||
// returned. The FD is not of the appropriate kind (i.e. not a DRM device),
|
||||
// gbm_create_device should reject it.
|
||||
let gbm = unsafe { gbm_create_device(fd.as_raw_fd()) };
|
||||
if gbm.is_null() {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(Device(Rc::new(DeviceInner { _fd: fd, gbm })))
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new buffer with the given metadata.
|
||||
pub fn create_buffer(&self,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: Format,
|
||||
usage: Flags)
|
||||
-> Result<Buffer, ()> {
|
||||
// This is safe because only a valid gbm_device is used and the return value is checked.
|
||||
let bo = unsafe { gbm_bo_create(self.0.gbm, width, height, format.0, usage.0) };
|
||||
if bo.is_null() {
|
||||
Err(())
|
||||
} else {
|
||||
Ok(Buffer(bo, self.clone()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An allocation from a `Device`.
|
||||
pub struct Buffer(*mut gbm_bo, Device);
|
||||
|
||||
impl Buffer {
|
||||
/// The device
|
||||
pub fn device(&self) -> &Device {
|
||||
&self.1
|
||||
}
|
||||
|
||||
/// Width in pixels.
|
||||
pub fn width(&self) -> u32 {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { gbm_bo_get_width(self.0) }
|
||||
}
|
||||
|
||||
/// Height in pixels.
|
||||
pub fn height(&self) -> u32 {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { gbm_bo_get_height(self.0) }
|
||||
}
|
||||
|
||||
/// Length in bytes of one row of the buffer.
|
||||
pub fn stride(&self) -> u32 {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { gbm_bo_get_stride(self.0) }
|
||||
}
|
||||
|
||||
/// Length in bytes of the stride or tiling.
|
||||
pub fn stride_or_tiling(&self) -> u32 {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { gbm_bo_get_stride_or_tiling(self.0) }
|
||||
}
|
||||
|
||||
/// `Format` of the buffer.
|
||||
pub fn format(&self) -> Format {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { Format(gbm_bo_get_format(self.0)) }
|
||||
}
|
||||
|
||||
/// Format modifier flags for the buffer.
|
||||
pub fn format_modifier(&self) -> u64 {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { gbm_bo_get_format_modifier(self.0) }
|
||||
}
|
||||
|
||||
/// Number of planes present in this buffer.
|
||||
pub fn num_planes(&self) -> usize {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { gbm_bo_get_num_planes(self.0) }
|
||||
}
|
||||
|
||||
/// 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.
|
||||
match unsafe { gbm_bo_get_plane_fd(self.0, plane) } {
|
||||
fd if fd >= 0 => Ok(unsafe { File::from_raw_fd(fd) }),
|
||||
ret => Err(ret),
|
||||
}
|
||||
}
|
||||
|
||||
/// Reads the given subsection of the buffer to `dst`.
|
||||
pub fn read_to_volatile(&self,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
plane: usize,
|
||||
dst: VolatileSlice)
|
||||
-> Result<(), ()> {
|
||||
let mut stride = 0;
|
||||
let mut map_data = null_mut();
|
||||
// Safe because only a valid gbm_bo object is used and the return value is checked. Only
|
||||
// pointers coerced from stack references are used for returned values, and we trust gbm to
|
||||
// only write as many bytes as the size of the pointed to values.
|
||||
let mapping = unsafe {
|
||||
gbm_bo_map(self.0,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
GBM_BO_TRANSFER_READ,
|
||||
&mut stride,
|
||||
&mut map_data,
|
||||
plane)
|
||||
};
|
||||
if mapping == MAP_FAILED {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let copy_size = (y as u64) * (stride as u64);
|
||||
|
||||
let res = if copy_size <= dst.size() {
|
||||
// The two buffers can not be overlapping because we just made a new mapping in this
|
||||
// scope.
|
||||
unsafe {
|
||||
copy_nonoverlapping(mapping as *mut u8, dst.as_ptr(), copy_size as usize);
|
||||
}
|
||||
Ok(())
|
||||
} else {
|
||||
Err(())
|
||||
};
|
||||
|
||||
// safe because the gbm_bo is assumed to be valid and the map_data is the same one given by
|
||||
// gbm_bo_map.
|
||||
unsafe {
|
||||
gbm_bo_unmap(self.0, map_data);
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
/// Writes to the given subsection of the buffer from `src`.
|
||||
pub fn write_from_slice(&self,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
plane: usize,
|
||||
src: &[u8])
|
||||
-> Result<(), ()> {
|
||||
let mut stride = 0;
|
||||
let mut map_data = null_mut();
|
||||
// Safe because only a valid gbm_bo object is used and the return value is checked. Only
|
||||
// pointers coerced from stack references are used for returned values, and we trust gbm to
|
||||
// only write as many bytes as the size of the pointed to values.
|
||||
let mapping = unsafe {
|
||||
gbm_bo_map(self.0,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
GBM_BO_TRANSFER_WRITE,
|
||||
&mut stride,
|
||||
&mut map_data,
|
||||
plane)
|
||||
};
|
||||
if mapping == MAP_FAILED {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let copy_size = (height as u64) * (stride as u64);
|
||||
let copy_sg_size = min(src.len() as u64, copy_size);
|
||||
|
||||
// The two buffers can not be overlapping because we just made a new mapping in this scope.
|
||||
unsafe {
|
||||
copy_nonoverlapping(src.as_ptr(), mapping as *mut u8, copy_sg_size as usize);
|
||||
}
|
||||
|
||||
// safe because the gbm_bo is assumed to be valid and the map_data is the same one given by
|
||||
// gbm_bo_map.
|
||||
unsafe {
|
||||
gbm_bo_unmap(self.0, map_data);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Writes to the given subsection of the buffer from `sgs`.
|
||||
pub fn write_from_sg<'a, S: Iterator<Item = VolatileSlice<'a>>>(&self,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
plane: usize,
|
||||
sgs: S)
|
||||
-> Result<(), ()> {
|
||||
let mut stride = 0;
|
||||
let mut map_data = null_mut();
|
||||
// Safe because only a valid gbm_bo object is used and the return value is checked. Only
|
||||
// pointers coerced from stack references are used for returned values, and we trust gbm to
|
||||
// only write as many bytes as the size of the pointed to values.
|
||||
let mut mapping = unsafe {
|
||||
gbm_bo_map(self.0,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
GBM_BO_TRANSFER_WRITE,
|
||||
&mut stride,
|
||||
&mut map_data,
|
||||
plane)
|
||||
};
|
||||
if mapping == MAP_FAILED {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
let mut copy_size = (height as u64) * (stride as u64);
|
||||
|
||||
for sg in sgs {
|
||||
let copy_sg_size = min(sg.size(), copy_size);
|
||||
// The two buffers can not be overlapping because we just made a new mapping in this
|
||||
// scope.
|
||||
unsafe {
|
||||
copy_nonoverlapping(sg.as_ptr(), mapping as *mut u8, copy_sg_size as usize);
|
||||
}
|
||||
|
||||
mapping = mapping.wrapping_offset(copy_sg_size as isize);
|
||||
copy_size -= copy_sg_size;
|
||||
if copy_size == 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// safe because the gbm_bo is assumed to be valid and the map_data is the same one given by
|
||||
// gbm_bo_map.
|
||||
unsafe {
|
||||
gbm_bo_unmap(self.0, map_data);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Buffer {
|
||||
fn drop(&mut self) {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { gbm_bo_destroy(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for Buffer {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
// This is always safe to call with a valid gbm_bo pointer.
|
||||
unsafe { gbm_bo_get_fd(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use std::fmt::Write;
|
||||
use data_model::VolatileMemory;
|
||||
|
||||
#[test]
|
||||
fn format_debug() {
|
||||
let f = Format::new(b'X', b'R', b'2', b'4');
|
||||
let mut buf = String::new();
|
||||
write!(&mut buf, "{:?}", f).unwrap();
|
||||
assert_eq!(buf, "fourcc(XR24)");
|
||||
|
||||
let f = Format::new(0, 1, 2, 16);
|
||||
let mut buf = String::new();
|
||||
write!(&mut buf, "{:?}", f).unwrap();
|
||||
assert_eq!(buf, "fourcc(0x00010210)");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // no access to /dev/dri
|
||||
fn open_device() {
|
||||
let drm_card = File::open("/dev/dri/card0").expect("failed to open card");
|
||||
Device::new(drm_card).expect("failed to create device with card");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // no access to /dev/dri
|
||||
fn create_buffer() {
|
||||
let drm_card = File::open("/dev/dri/card0").expect("failed to open card");
|
||||
let device = Device::new(drm_card).expect("failed to create device with card");
|
||||
let bo = device
|
||||
.create_buffer(1024,
|
||||
512,
|
||||
Format::new(b'X', b'R', b'2', b'4'),
|
||||
Flags::empty().use_scanout(true))
|
||||
.expect("failed to create buffer");
|
||||
|
||||
assert_eq!(bo.width(), 1024);
|
||||
assert_eq!(bo.height(), 512);
|
||||
assert_eq!(bo.format(), Format::new(b'X', b'R', b'2', b'4'));
|
||||
assert_eq!(bo.num_planes(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore] // no access to /dev/dri
|
||||
fn export_buffer() {
|
||||
let drm_card = File::open("/dev/dri/card0").expect("failed to open card");
|
||||
let device = Device::new(drm_card).expect("failed to create device with card");
|
||||
let bo = device
|
||||
.create_buffer(1024,
|
||||
1024,
|
||||
Format::new(b'X', b'R', b'2', b'4'),
|
||||
Flags::empty().use_scanout(true))
|
||||
.expect("failed to create buffer");
|
||||
bo.export_plane_fd(0).expect("failed to export plane");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
#[ignore] // no access to /dev/dri
|
||||
fn buffer_transfer() {
|
||||
let drm_card = File::open("/dev/dri/card0").expect("failed to open card");
|
||||
let device = Device::new(drm_card).expect("failed to create device with card");
|
||||
let bo = device
|
||||
.create_buffer(1024,
|
||||
1024,
|
||||
Format::new(b'X', b'R', b'2', b'4'),
|
||||
Flags::empty().use_scanout(true).use_linear(true))
|
||||
.expect("failed to create buffer");
|
||||
let mut dst: Vec<u8> = Vec::new();
|
||||
dst.resize((bo.stride() * bo.height()) as usize, 0x4A);
|
||||
let dst_len = dst.len() as u64;
|
||||
bo.write_from_slice(0, 0, 1024, 1024, 0, dst.as_slice())
|
||||
.expect("failed to read bo");
|
||||
bo.read_to_volatile(0,
|
||||
0,
|
||||
1024,
|
||||
1024,
|
||||
0,
|
||||
dst.as_mut_slice().get_slice(0, dst_len).unwrap())
|
||||
.expect("failed to read bo");
|
||||
assert!(dst.iter().all(|&x| x == 0x4A));
|
||||
}
|
||||
}
|
209
gpu_buffer/src/raw.rs
Normal file
209
gpu_buffer/src/raw.rs
Normal file
|
@ -0,0 +1,209 @@
|
|||
// 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.
|
||||
|
||||
// Generated with bindgen --whitelist-function='gbm_.*' --whitelist-type='gbm_.*' minigbm/gbm.h
|
||||
// Hand-modified by zachr
|
||||
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::os::raw::{c_int, c_char, c_void};
|
||||
|
||||
/// \file gbm.h
|
||||
/// \brief Generic Buffer Manager
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct gbm_device {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct gbm_bo {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct gbm_surface {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
/// Abstraction representing the handle to a buffer allocated by the
|
||||
/// manager
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone)]
|
||||
pub union gbm_bo_handle {
|
||||
pub ptr: *mut c_void,
|
||||
pub s32: i32,
|
||||
pub u32: u32,
|
||||
pub s64: i64,
|
||||
pub u64: u64,
|
||||
_bindgen_union_align: u64,
|
||||
}
|
||||
|
||||
/// Buffer is going to be presented to the screen using an API such as KMS
|
||||
pub const GBM_BO_USE_SCANOUT: gbm_bo_flags = 1;
|
||||
/// Buffer is going to be used as cursor
|
||||
pub const GBM_BO_USE_CURSOR: gbm_bo_flags = 2;
|
||||
/// Deprecated
|
||||
pub const GBM_BO_USE_CURSOR_64X64: gbm_bo_flags = 2;
|
||||
/// Buffer is to be used for rendering - for example it is going to be used
|
||||
/// as the storage for a color buffer
|
||||
pub const GBM_BO_USE_RENDERING: gbm_bo_flags = 4;
|
||||
/// Deprecated
|
||||
pub const GBM_BO_USE_WRITE: gbm_bo_flags = 8;
|
||||
/// Buffer is guaranteed to be laid out linearly in memory. That is, the
|
||||
/// buffer is laid out as an array with 'height' blocks, each block with
|
||||
/// length 'stride'. Each stride is in the same order as the rows of the
|
||||
/// buffer. This is intended to be used with buffers that will be accessed
|
||||
/// via dma-buf mmap().
|
||||
pub const GBM_BO_USE_LINEAR: gbm_bo_flags = 16;
|
||||
/// The buffer will be used as a texture that will be sampled from.
|
||||
pub const GBM_BO_USE_TEXTURING: gbm_bo_flags = 32;
|
||||
/// The buffer will be written to by a camera subsystem.
|
||||
pub const GBM_BO_USE_CAMERA_WRITE: gbm_bo_flags = 64;
|
||||
/// The buffer will be read from by a camera subsystem.
|
||||
pub const GBM_BO_USE_CAMERA_READ: gbm_bo_flags = 128;
|
||||
/// Buffer inaccessible to unprivileged users.
|
||||
pub const GBM_BO_USE_PROTECTED: gbm_bo_flags = 256;
|
||||
/// These flags specify the frequency of software access. These flags do not
|
||||
/// guarantee the buffer is linear, but do guarantee gbm_bo_map(..) will
|
||||
/// present a linear view.
|
||||
pub const GBM_BO_USE_SW_READ_OFTEN: gbm_bo_flags = 512;
|
||||
/// These flags specify the frequency of software access. These flags do not
|
||||
/// guarantee the buffer is linear, but do guarantee gbm_bo_map(..) will
|
||||
/// present a linear view.
|
||||
pub const GBM_BO_USE_SW_READ_RARELY: gbm_bo_flags = 1024;
|
||||
/// These flags specify the frequency of software access. These flags do not
|
||||
/// guarantee the buffer is linear, but do guarantee gbm_bo_map(..) will
|
||||
/// present a linear view.
|
||||
pub const GBM_BO_USE_SW_WRITE_OFTEN: gbm_bo_flags = 2048;
|
||||
/// These flags specify the frequency of software access. These flags do not
|
||||
/// guarantee the buffer is linear, but do guarantee gbm_bo_map(..) will
|
||||
/// present a linear view.
|
||||
pub const GBM_BO_USE_SW_WRITE_RARELY: gbm_bo_flags = 4096;
|
||||
/// Flags to indicate the intended use for the buffer - these are passed into
|
||||
/// gbm_bo_create(). The caller must set the union of all the flags that are
|
||||
/// appropriate
|
||||
///
|
||||
/// \sa Use gbm_device_is_format_supported() to check if the combination of format
|
||||
/// and use flags are supported
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type gbm_bo_flags = u32;
|
||||
|
||||
#[link(name = "gbm")]
|
||||
extern "C" {
|
||||
pub fn gbm_device_get_fd(gbm: *mut gbm_device) -> c_int;
|
||||
pub fn gbm_device_get_backend_name(gbm: *mut gbm_device) -> *const c_char;
|
||||
pub fn gbm_device_is_format_supported(gbm: *mut gbm_device, format: u32, usage: u32) -> c_int;
|
||||
pub fn gbm_device_destroy(gbm: *mut gbm_device);
|
||||
pub fn gbm_create_device(fd: c_int) -> *mut gbm_device;
|
||||
pub fn gbm_bo_create(gbm: *mut gbm_device,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: u32,
|
||||
flags: u32)
|
||||
-> *mut gbm_bo;
|
||||
pub fn gbm_bo_create_with_modifiers(gbm: *mut gbm_device,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: u32,
|
||||
modifiers: *const u64,
|
||||
count: u32)
|
||||
-> *mut gbm_bo;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone )]
|
||||
pub struct gbm_import_fd_data {
|
||||
pub fd: c_int,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub stride: u32,
|
||||
pub format: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone )]
|
||||
pub struct gbm_import_fd_planar_data {
|
||||
pub fds: [c_int; 4usize],
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub format: u32,
|
||||
pub strides: [u32; 4usize],
|
||||
pub offsets: [u32; 4usize],
|
||||
pub format_modifiers: [u64; 4usize],
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn gbm_bo_import(gbm: *mut gbm_device,
|
||||
type_: u32,
|
||||
buffer: *mut c_void,
|
||||
usage: u32)
|
||||
-> *mut gbm_bo;
|
||||
}
|
||||
|
||||
/// Buffer contents read back (or accessed directly) at transfer
|
||||
/// create time.
|
||||
pub const GBM_BO_TRANSFER_READ: gbm_bo_transfer_flags = 1;
|
||||
/// Buffer contents will be written back at unmap time
|
||||
/// (or modified as a result of being accessed directly).
|
||||
pub const GBM_BO_TRANSFER_WRITE: gbm_bo_transfer_flags = 2;
|
||||
/// Read/modify/write
|
||||
pub const GBM_BO_TRANSFER_READ_WRITE: gbm_bo_transfer_flags = 3;
|
||||
|
||||
/// Flags to indicate the type of mapping for the buffer - these are
|
||||
/// passed into gbm_bo_map(). The caller must set the union of all the
|
||||
/// flags that are appropriate.
|
||||
///
|
||||
/// These flags are independent of the GBM_BO_USE_* creation flags. However,
|
||||
/// mapping the buffer may require copying to/from a staging buffer.
|
||||
///
|
||||
/// See also: pipe_transfer_usage
|
||||
#[allow(non_camel_case_types)]
|
||||
pub type gbm_bo_transfer_flags = u32;
|
||||
|
||||
extern "C" {
|
||||
pub fn gbm_bo_map(bo: *mut gbm_bo,
|
||||
x: u32,
|
||||
y: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
flags: u32,
|
||||
stride: *mut u32,
|
||||
map_data: *mut *mut c_void,
|
||||
plane: usize)
|
||||
-> *mut c_void;
|
||||
pub fn gbm_bo_unmap(bo: *mut gbm_bo, map_data: *mut c_void);
|
||||
pub fn gbm_bo_get_width(bo: *mut gbm_bo) -> u32;
|
||||
pub fn gbm_bo_get_height(bo: *mut gbm_bo) -> u32;
|
||||
pub fn gbm_bo_get_stride(bo: *mut gbm_bo) -> u32;
|
||||
pub fn gbm_bo_get_stride_or_tiling(bo: *mut gbm_bo) -> u32;
|
||||
pub fn gbm_bo_get_format(bo: *mut gbm_bo) -> u32;
|
||||
pub fn gbm_bo_get_format_modifier(bo: *mut gbm_bo) -> u64;
|
||||
pub fn gbm_bo_get_device(bo: *mut gbm_bo) -> *mut gbm_device;
|
||||
pub fn gbm_bo_get_handle(bo: *mut gbm_bo) -> gbm_bo_handle;
|
||||
pub fn gbm_bo_get_fd(bo: *mut gbm_bo) -> c_int;
|
||||
pub fn gbm_bo_get_num_planes(bo: *mut gbm_bo) -> usize;
|
||||
pub fn gbm_bo_get_plane_handle(bo: *mut gbm_bo, plane: usize) -> gbm_bo_handle;
|
||||
pub fn gbm_bo_get_plane_fd(bo: *mut gbm_bo, plane: usize) -> c_int;
|
||||
pub fn gbm_bo_get_plane_offset(bo: *mut gbm_bo, plane: usize) -> u32;
|
||||
pub fn gbm_bo_get_plane_size(bo: *mut gbm_bo, plane: usize) -> u32;
|
||||
pub fn gbm_bo_get_plane_stride(bo: *mut gbm_bo, plane: usize) -> u32;
|
||||
pub fn gbm_bo_get_plane_format_modifier(bo: *mut gbm_bo, plane: usize) -> u64;
|
||||
// Did not generate cleanly by bindgen. Redone manually by zachr.
|
||||
pub fn gbm_bo_set_user_data(bo: *mut gbm_bo,
|
||||
data: *mut c_void,
|
||||
destroy_user_data: extern "C" fn(bo: *mut gbm_bo,
|
||||
data: *mut c_void));
|
||||
pub fn gbm_bo_get_user_data(bo: *mut gbm_bo) -> *mut c_void;
|
||||
pub fn gbm_bo_destroy(bo: *mut gbm_bo);
|
||||
pub fn gbm_surface_create(gbm: *mut gbm_device,
|
||||
width: u32,
|
||||
height: u32,
|
||||
format: u32,
|
||||
flags: u32)
|
||||
-> *mut gbm_surface;
|
||||
pub fn gbm_surface_lock_front_buffer(surface: *mut gbm_surface) -> *mut gbm_bo;
|
||||
pub fn gbm_surface_release_buffer(surface: *mut gbm_surface, bo: *mut gbm_bo);
|
||||
pub fn gbm_surface_has_free_buffers(surface: *mut gbm_surface) -> c_int;
|
||||
pub fn gbm_surface_destroy(surface: *mut gbm_surface);
|
||||
}
|
Loading…
Reference in a new issue