From 6f6854312df5691763f3ee80be84fde16e82f6b8 Mon Sep 17 00:00:00 2001 From: Zach Reizner Date: Wed, 25 Apr 2018 17:49:56 -0700 Subject: [PATCH] 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 Tested-by: Zach Reizner Reviewed-by: Zach Reizner Reviewed-by: Dylan Reid --- Cargo.lock | 8 + Cargo.toml | 1 + gpu_buffer/Cargo.toml | 7 + gpu_buffer/src/lib.rs | 553 ++++++++++++++++++++++++++++++++++++++++++ gpu_buffer/src/raw.rs | 209 ++++++++++++++++ 5 files changed, 778 insertions(+) create mode 100644 gpu_buffer/Cargo.toml create mode 100644 gpu_buffer/src/lib.rs create mode 100644 gpu_buffer/src/raw.rs diff --git a/Cargo.lock b/Cargo.lock index 2b8a4fa2c4..33f2d56852 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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" diff --git a/Cargo.toml b/Cargo.toml index 1771719caa..b6db1eb360 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" } diff --git a/gpu_buffer/Cargo.toml b/gpu_buffer/Cargo.toml new file mode 100644 index 0000000000..11b47c492f --- /dev/null +++ b/gpu_buffer/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "gpu_buffer" +version = "0.1.0" +authors = ["The Chromium OS Authors"] + +[dependencies] +data_model = { path = "../data_model" } diff --git a/gpu_buffer/src/lib.rs b/gpu_buffer/src/lib.rs new file mode 100644 index 0000000000..6d0cfa9a89 --- /dev/null +++ b/gpu_buffer/src/lib.rs @@ -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> { +//! 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 for Format { + fn from(u: u32) -> Format { + Format(u) + } +} + +impl From 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); + +impl Device { + /// Returns a new `Device` using the given `fd` opened from a device in `/dev/dri/`. + pub fn new(fd: File) -> Result { + // 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 { + // 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 { + // 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>>(&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 = 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)); + } +} diff --git a/gpu_buffer/src/raw.rs b/gpu_buffer/src/raw.rs new file mode 100644 index 0000000000..e5e258aa9f --- /dev/null +++ b/gpu_buffer/src/raw.rs @@ -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); +}