rutabaga_gfx: rutabaga_gralloc: a shimmering beacon of hope

rutabaga_gralloc is a cross-platform, Rust-based buffer
manager.

The rationale for this change is:

1) For the {cross-domain, wayland} context type, we need to
have a good story for the crucial "wl-dmabuf" feature.  As
minigbm has been thoroughly tested on ChromeOS and currently
powers the "wl-dmabuf" feature, it only makes sense for us to
have a path to minigbm for the cross-domain prototype.  This
will be used by Sommelier.

2) While minigbm allocation works well on Chromebooks, it is
not sufficient for cross-platform purposes.  For their Virtual
Graphics Interface (VGI) initiative, Android graphics
virtualization experts have expressed their desire for a Vulkan
based allocator.  This will to go alongside cros_gralloc in
minigbm, which is considered by many to be the ""world's
premiere gralloc implementation".

3) Android graphics virtualization experts have expressed their
desire for vkMapMemory(..) to be used when crosvm is in
multi-process mode.  Currently, only dma-buf mmap() is supported
for zero-copy blobs in multi-process mode.  dma-buf mmap() is not
guaranteed to work on Nvidia (a "must have" for Cuttlefish) or
any other driver for that matter (we *make* it work for ChromeOS).
Possibly only solution: vkMapMemory ;-)

With these goals in mind, here's a summary of the revelant changes:

* Renamed the {gpu_allocator.rs, GpuMemoryAllocator trait} to be
  {gralloc.rs, Gralloc trait}.

* Moved all GPU allocation out of the resources crate and into
  the rutabaga_gfx crate.  This will allow the resources crate to
  be focused on managing resources for virtual machines.

* Moved the gpu_buffer crate into the gralloc module in the
  rutabaga_gfx crate.  The same functionality is now under
  "minigbm.rs", "minigbm_bindings.rs" and "rendernode.rs"

* Added an optional dependency on vulkano.rs.  vulkano.rs is a safe
  Rust wrapper around the Vulkan api [a].  It's emphasis on type
  safety makes a good fit for crosvm, though there are other high
  quality crates out there (gfx-rs, ash.rs).  Though development
  has slowed down, it should satisfy goals (2) and (3) quite easily.

* Added a system_gralloc implementation based on memfd.  This can be
  used when minigbm or Vulkano features are not used, to replicate the
  highly useful "wl-shm" feature in Sommelier.  Astute observers will
  note this can also enable seamless Wayland windowing without GPU
  features for Android too.  Some minor changes to the base crate were
  needed.

* Cut down on the amount of DrmFormats to the subset needed by
  Sommelier and cros_gralloc.

* Moved checked arithmetic into it's own file.

* Internally renamed to "wl-dmabuf" feature to be the "minigbm"
  feature.  This is because "wl-dmabuf" has a dependency on minigbm.

* Small rutabaga_gfx cleanups

[a] https://github.com/vulkano-rs/vulkano/blob/master/DESIGN.md

BUG=b:146066070, b:173630595, b:150239451
TEST=launch virtual machine with 2D mode
TEST=launch virtual machine with 3D mode
TEST=run sommelier with "wl-dmabuf" and "wl-shm"

Change-Id: I693a39cef64cd98e56d843d3c60caa7983d4d6e1
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2626487
Tested-by: Gurchetan Singh <gurchetansingh@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org>
diff --git a/Cargo.lock b/Cargo.lock
index b0be54f..6943bbe 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -184,7 +184,6 @@
  "disk",
  "enumn",
  "gdbstub",
- "gpu_buffer",
  "hypervisor",
  "kernel_cmdline",
  "kernel_loader",
@@ -254,7 +253,6 @@
  "disk",
  "enumn",
  "fuse",
- "gpu_buffer",
  "gpu_display",
  "hypervisor",
  "kvm_sys",
@@ -446,14 +444,6 @@
 ]
 
 [[package]]
-name = "gpu_buffer"
-version = "0.1.0"
-dependencies = [
- "base",
- "data_model",
-]
-
-[[package]]
 name = "gpu_display"
 version = "0.1.0"
 dependencies = [
@@ -554,9 +544,9 @@
 
 [[package]]
 name = "libc"
-version = "0.2.65"
+version = "0.2.81"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
+checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb"
 
 [[package]]
 name = "libchromeos"
@@ -868,7 +858,6 @@
 version = "0.1.0"
 dependencies = [
  "base",
- "gpu_buffer",
  "libc",
  "msg_socket",
 ]
@@ -1030,6 +1019,7 @@
  "libc",
  "msg_socket",
  "resources",
+ "rutabaga_gfx",
  "sync",
  "vm_memory",
 ]
diff --git a/Cargo.toml b/Cargo.toml
index 5861036..e97fe17 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -44,7 +44,7 @@
 tpm = ["devices/tpm"]
 video-decoder = ["devices/video-decoder"]
 video-encoder = ["devices/video-encoder"]
-wl-dmabuf = ["devices/wl-dmabuf", "gpu_buffer", "resources/wl-dmabuf"]
+wl-dmabuf = ["devices/minigbm"]
 x = ["devices/x"]
 virgl_renderer_next = ["rutabaga_gfx/virgl_renderer_next"]
 composite-disk = ["protos/composite-disk", "protobuf", "disk/composite-disk"]
@@ -64,8 +64,7 @@
 disk = { path = "disk" }
 enumn = { path = "enumn" }
 gdbstub = { version = "0.4.0", optional = true }
-gpu_buffer = { path = "gpu_buffer", optional = true }
-rutabaga_gfx = { path = "rutabaga_gfx", optional = true }
+rutabaga_gfx = { path = "rutabaga_gfx"}
 hypervisor = { path = "hypervisor" }
 kernel_cmdline = { path = "kernel_cmdline" }
 kernel_loader = { path = "kernel_loader" }
diff --git a/aarch64/src/lib.rs b/aarch64/src/lib.rs
index 1322f9f..db0ac95 100644
--- a/aarch64/src/lib.rs
+++ b/aarch64/src/lib.rs
@@ -234,8 +234,8 @@
             VmImage::Bios(_) => true,
             _ => false,
         };
-        let mut resources =
-            Self::get_resource_allocator(components.memory_size, components.wayland_dmabuf);
+
+        let mut resources = Self::get_resource_allocator(components.memory_size);
         let mem = Self::setup_memory(components.memory_size)?;
         let mut vm = create_vm(mem.clone()).map_err(|e| Error::CreateVm(Box::new(e)))?;
 
@@ -424,12 +424,12 @@
     }
 
     /// Returns a system resource allocator.
-    fn get_resource_allocator(mem_size: u64, gpu_allocation: bool) -> SystemAllocator {
+    fn get_resource_allocator(mem_size: u64) -> SystemAllocator {
         let (high_mmio_base, high_mmio_size) = Self::get_high_mmio_base_size(mem_size);
         SystemAllocator::builder()
             .add_high_mmio_addresses(high_mmio_base, high_mmio_size)
             .add_low_mmio_addresses(AARCH64_MMIO_BASE, AARCH64_MMIO_SIZE)
-            .create_allocator(AARCH64_IRQ_BASE, gpu_allocation)
+            .create_allocator(AARCH64_IRQ_BASE)
             .unwrap()
     }
 
diff --git a/base/src/shm.rs b/base/src/shm.rs
index 138991a..36c6f7e 100644
--- a/base/src/shm.rs
+++ b/base/src/shm.rs
@@ -76,3 +76,9 @@
         self.0.as_raw_fd()
     }
 }
+
+impl Into<File> for SharedMemory {
+    fn into(self) -> File {
+        self.0.into()
+    }
+}
diff --git a/devices/Cargo.toml b/devices/Cargo.toml
index bd38b12..a9aa3c7 100644
--- a/devices/Cargo.toml
+++ b/devices/Cargo.toml
@@ -6,11 +6,11 @@
 
 [features]
 audio = []
-gpu = ["gpu_buffer", "gpu_display","rutabaga_gfx"]
+gpu = ["gpu_display","rutabaga_gfx"]
 tpm = ["protos/trunks", "tpm2"]
 video-decoder = ["libvda"]
 video-encoder = ["libvda"]
-wl-dmabuf = []
+minigbm = ["rutabaga_gfx/minigbm"]
 x = ["gpu_display/x"]
 virgl_renderer = ["gpu", "rutabaga_gfx/virgl_renderer"]
 gfxstream = ["gpu", "rutabaga_gfx/gfxstream"]
@@ -24,7 +24,6 @@
 disk = { path = "../disk" }
 enumn = { path = "../enumn" }
 fuse = {path = "../fuse" }
-gpu_buffer = { path = "../gpu_buffer", optional = true }
 gpu_display = { path = "../gpu_display", optional = true }
 rutabaga_gfx = { path = "../rutabaga_gfx", optional = true }
 hypervisor = { path = "../hypervisor" }
diff --git a/devices/src/irqchip/kvm/x86_64.rs b/devices/src/irqchip/kvm/x86_64.rs
index 8e8e1de..8b6d546 100644
--- a/devices/src/irqchip/kvm/x86_64.rs
+++ b/devices/src/irqchip/kvm/x86_64.rs
@@ -883,7 +883,7 @@
             .add_io_addresses(0xc000, 0x10000)
             .add_low_mmio_addresses(0, 2048)
             .add_high_mmio_addresses(2048, 4096)
-            .create_allocator(5, false)
+            .create_allocator(5)
             .expect("failed to create SystemAllocator");
 
         // setup an event and a resample event for irq line 1
@@ -1001,7 +1001,7 @@
             .add_io_addresses(0xc000, 0x10000)
             .add_low_mmio_addresses(0, 2048)
             .add_high_mmio_addresses(2048, 4096)
-            .create_allocator(5, false)
+            .create_allocator(5)
             .expect("failed to create SystemAllocator");
 
         // setup an event and a resample event for irq line 1
diff --git a/devices/src/pci/ac97.rs b/devices/src/pci/ac97.rs
index a3762bb..bd713b0 100644
--- a/devices/src/pci/ac97.rs
+++ b/devices/src/pci/ac97.rs
@@ -386,7 +386,7 @@
             .add_io_addresses(0x1000_0000, 0x1000_0000)
             .add_low_mmio_addresses(0x2000_0000, 0x1000_0000)
             .add_high_mmio_addresses(0x3000_0000, 0x1000_0000)
-            .create_allocator(5, false)
+            .create_allocator(5)
             .unwrap();
         ac97_dev.assign_address(PciAddress {
             bus: 0,
diff --git a/devices/src/virtio/gpu/mod.rs b/devices/src/virtio/gpu/mod.rs
index fb2d427..7b2cf7c 100644
--- a/devices/src/virtio/gpu/mod.rs
+++ b/devices/src/virtio/gpu/mod.rs
@@ -25,13 +25,12 @@
 
 use data_model::*;
 
-use gpu_buffer::Format;
 pub use gpu_display::EventDevice;
 use gpu_display::*;
 use rutabaga_gfx::{
-    GfxstreamFlags, ResourceCreate3D, ResourceCreateBlob, RutabagaBuilder, RutabagaComponentType,
-    RutabagaFenceData, Transfer3D, VirglRendererFlags, RUTABAGA_PIPE_BIND_RENDER_TARGET,
-    RUTABAGA_PIPE_TEXTURE_2D,
+    DrmFormat, GfxstreamFlags, ResourceCreate3D, ResourceCreateBlob, RutabagaBuilder,
+    RutabagaComponentType, RutabagaFenceData, Transfer3D, VirglRendererFlags,
+    RUTABAGA_PIPE_BIND_RENDER_TARGET, RUTABAGA_PIPE_TEXTURE_2D,
 };
 
 use msg_socket::{MsgReceiver, MsgSender};
@@ -115,7 +114,7 @@
 pub struct VirtioScanoutBlobData {
     pub width: u32,
     pub height: u32,
-    pub drm_format: Format,
+    pub drm_format: DrmFormat,
     pub strides: [u32; 4],
     pub offsets: [u32; 4],
 }
@@ -481,8 +480,8 @@
                 // As of v4.19, virtio-gpu kms only really uses these formats.  If that changes,
                 // the following may have to change too.
                 let drm_format = match virtio_gpu_format {
-                    VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM => Format::new(b'X', b'R', b'2', b'4'),
-                    VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM => Format::new(b'A', b'R', b'2', b'4'),
+                    VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM => DrmFormat::new(b'X', b'R', b'2', b'4'),
+                    VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM => DrmFormat::new(b'A', b'R', b'2', b'4'),
                     _ => {
                         error!("unrecognized virtio-gpu format {}", virtio_gpu_format);
                         return Err(GpuResponse::ErrUnspec);
diff --git a/devices/src/virtio/wl.rs b/devices/src/virtio/wl.rs
index de0181e..8359b44 100644
--- a/devices/src/virtio/wl.rs
+++ b/devices/src/virtio/wl.rs
@@ -37,7 +37,7 @@
 use std::fs::File;
 use std::io::{self, Read, Seek, SeekFrom, Write};
 use std::mem::size_of;
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 use std::os::raw::{c_uint, c_ulonglong};
 use std::os::unix::net::UnixStream;
 use std::path::{Path, PathBuf};
@@ -46,28 +46,26 @@
 use std::thread;
 use std::time::Duration;
 
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 use libc::{EBADF, EINVAL};
 
 use data_model::VolatileMemoryError;
 use data_model::*;
 
-#[cfg(feature = "wl-dmabuf")]
-use base::ioctl_iow_nr;
 use base::{
     error, pipe, round_up_to_page_size, warn, AsRawDescriptor, Error, Event, FileFlags,
     FromRawDescriptor, PollToken, RawDescriptor, Result, ScmSocket, SharedMemory, SharedMemoryUnix,
     WaitContext,
 };
+#[cfg(feature = "minigbm")]
+use base::{ioctl_iow_nr, ioctl_with_ref};
 #[cfg(feature = "gpu")]
 use base::{IntoRawDescriptor, SafeDescriptor};
 use msg_socket::{MsgError, MsgReceiver, MsgSender};
-#[cfg(feature = "wl-dmabuf")]
-use resources::GpuMemoryDesc;
 use vm_memory::{GuestMemory, GuestMemoryError};
 
-#[cfg(feature = "wl-dmabuf")]
-use base::ioctl_with_ref;
+#[cfg(feature = "minigbm")]
+use vm_control::GpuMemoryDesc;
 
 use super::resource_bridge::*;
 use super::{DescriptorChain, Interrupt, Queue, Reader, VirtioDevice, Writer, TYPE_WL};
@@ -83,16 +81,16 @@
 const VIRTIO_WL_CMD_VFD_NEW_CTX: u32 = 260;
 const VIRTIO_WL_CMD_VFD_NEW_PIPE: u32 = 261;
 const VIRTIO_WL_CMD_VFD_HUP: u32 = 262;
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 const VIRTIO_WL_CMD_VFD_NEW_DMABUF: u32 = 263;
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 const VIRTIO_WL_CMD_VFD_DMABUF_SYNC: u32 = 264;
 #[cfg(feature = "gpu")]
 const VIRTIO_WL_CMD_VFD_SEND_FOREIGN_ID: u32 = 265;
 const VIRTIO_WL_CMD_VFD_NEW_CTX_NAMED: u32 = 266;
 const VIRTIO_WL_RESP_OK: u32 = 4096;
 const VIRTIO_WL_RESP_VFD_NEW: u32 = 4097;
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 const VIRTIO_WL_RESP_VFD_NEW_DMABUF: u32 = 4098;
 const VIRTIO_WL_RESP_ERR: u32 = 4352;
 const VIRTIO_WL_RESP_OUT_OF_MEMORY: u32 = 4353;
@@ -117,20 +115,20 @@
 const IN_BUFFER_LEN: usize =
     0x1000 - size_of::<CtrlVfdRecv>() - VIRTWL_SEND_MAX_ALLOCS * size_of::<Le32>();
 
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 const VIRTIO_WL_VFD_DMABUF_SYNC_VALID_FLAG_MASK: u32 = 0x7;
 
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 const DMA_BUF_IOCTL_BASE: c_uint = 0x62;
 
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 #[repr(C)]
 #[derive(Copy, Clone)]
 struct dma_buf_sync {
     flags: c_ulonglong,
 }
 
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 ioctl_iow_nr!(DMA_BUF_IOCTL_SYNC, DMA_BUF_IOCTL_BASE, 0, dma_buf_sync);
 
 const VIRTIO_WL_CTRL_VFD_SEND_KIND_LOCAL: u32 = 0;
@@ -166,7 +164,7 @@
         .map_err(WlError::WriteResponse)
 }
 
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 fn encode_vfd_new_dmabuf(
     writer: &mut Writer,
     vfd_id: u32,
@@ -245,7 +243,7 @@
             size,
             resp,
         } => encode_vfd_new(writer, resp, id, flags, pfn, size),
-        #[cfg(feature = "wl-dmabuf")]
+        #[cfg(feature = "minigbm")]
         WlResp::VfdNewDmabuf {
             id,
             flags,
@@ -387,7 +385,7 @@
 
 #[repr(C)]
 #[derive(Copy, Clone, Default)]
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 struct CtrlVfdNewDmabuf {
     hdr: CtrlHeader,
     id: Le32,
@@ -405,19 +403,19 @@
     offset2: Le32,
 }
 
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 unsafe impl DataInit for CtrlVfdNewDmabuf {}
 
 #[repr(C)]
 #[derive(Copy, Clone, Default)]
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 struct CtrlVfdDmabufSync {
     hdr: CtrlHeader,
     id: Le32,
     flags: Le32,
 }
 
-#[cfg(feature = "wl-dmabuf")]
+#[cfg(feature = "minigbm")]
 unsafe impl DataInit for CtrlVfdDmabufSync {}
 
 #[repr(C)]
@@ -504,7 +502,7 @@
         // is important for the `get_code` method.
         resp: bool,
     },
-    #[cfg(feature = "wl-dmabuf")]
+    #[cfg(feature = "minigbm")]
     VfdNewDmabuf {
         id: u32,
         flags: u32,
@@ -539,7 +537,7 @@
                     VIRTIO_WL_CMD_VFD_NEW
                 }
             }
-            #[cfg(feature = "wl-dmabuf")]
+            #[cfg(feature = "minigbm")]
             WlResp::VfdNewDmabuf { .. } => VIRTIO_WL_RESP_VFD_NEW_DMABUF,
             WlResp::VfdRecv { .. } => VIRTIO_WL_CMD_VFD_RECV,
             WlResp::VfdHup { .. } => VIRTIO_WL_CMD_VFD_HUP,
@@ -560,7 +558,7 @@
     remote_pipe: Option<File>,
     local_pipe: Option<(u32 /* flags */, File)>,
     slot: Option<(MemSlot, u64 /* pfn */, VmRequester)>,
-    #[cfg(feature = "wl-dmabuf")]
+    #[cfg(feature = "minigbm")]
     is_dmabuf: bool,
 }
 
@@ -611,7 +609,7 @@
         }
     }
 
-    #[cfg(feature = "wl-dmabuf")]
+    #[cfg(feature = "minigbm")]
     fn dmabuf(
         vm: VmRequester,
         width: u32,
@@ -643,7 +641,7 @@
         }
     }
 
-    #[cfg(feature = "wl-dmabuf")]
+    #[cfg(feature = "minigbm")]
     fn dmabuf_sync(&self, flags: u32) -> WlResult<()> {
         if !self.is_dmabuf {
             return Err(WlError::DmabufSync(io::Error::from_raw_os_error(EINVAL)));
@@ -978,7 +976,7 @@
         }
     }
 
-    #[cfg(feature = "wl-dmabuf")]
+    #[cfg(feature = "minigbm")]
     fn new_dmabuf(&mut self, id: u32, width: u32, height: u32, format: u32) -> WlResult<WlResp> {
         if id & VFD_ID_HOST_MASK != 0 {
             return Ok(WlResp::InvalidId);
@@ -1001,7 +999,7 @@
         }
     }
 
-    #[cfg(feature = "wl-dmabuf")]
+    #[cfg(feature = "minigbm")]
     fn dmabuf_sync(&mut self, vfd_id: u32, flags: u32) -> WlResult<WlResp> {
         if flags & !(VIRTIO_WL_VFD_DMABUF_SYNC_VALID_FLAG_MASK) != 0 {
             return Ok(WlResp::InvalidFlags);
@@ -1343,7 +1341,7 @@
                     .map_err(WlError::ParseDesc)?;
                 self.new_pipe(ctrl.id.into(), ctrl.flags.into())
             }
-            #[cfg(feature = "wl-dmabuf")]
+            #[cfg(feature = "minigbm")]
             VIRTIO_WL_CMD_VFD_NEW_DMABUF => {
                 let ctrl = reader
                     .read_obj::<CtrlVfdNewDmabuf>()
@@ -1355,7 +1353,7 @@
                     ctrl.format.into(),
                 )
             }
-            #[cfg(feature = "wl-dmabuf")]
+            #[cfg(feature = "minigbm")]
             VIRTIO_WL_CMD_VFD_DMABUF_SYNC => {
                 let ctrl = reader
                     .read_obj::<CtrlVfdDmabufSync>()
diff --git a/gpu_buffer/src/drm_formats.rs b/gpu_buffer/src/drm_formats.rs
deleted file mode 100644
index bad5646..0000000
--- a/gpu_buffer/src/drm_formats.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-
-#![allow(dead_code)]
-
-pub const DRM_FORMAT_C8: [u8; 4] = [b'C', b'8', b' ', b' '];
-pub const DRM_FORMAT_R8: [u8; 4] = [b'R', b'8', b' ', b' '];
-pub const DRM_FORMAT_R16: [u8; 4] = [b'R', b'1', b'6', b' '];
-pub const DRM_FORMAT_RG88: [u8; 4] = [b'R', b'G', b'8', b'8'];
-pub const DRM_FORMAT_GR88: [u8; 4] = [b'G', b'R', b'8', b'8'];
-pub const DRM_FORMAT_RG1616: [u8; 4] = [b'R', b'G', b'3', b'2'];
-pub const DRM_FORMAT_GR1616: [u8; 4] = [b'G', b'R', b'3', b'2'];
-pub const DRM_FORMAT_RGB332: [u8; 4] = [b'R', b'G', b'B', b'8'];
-pub const DRM_FORMAT_BGR233: [u8; 4] = [b'B', b'G', b'R', b'8'];
-pub const DRM_FORMAT_XRGB4444: [u8; 4] = [b'X', b'R', b'1', b'2'];
-pub const DRM_FORMAT_XBGR4444: [u8; 4] = [b'X', b'B', b'1', b'2'];
-pub const DRM_FORMAT_RGBX4444: [u8; 4] = [b'R', b'X', b'1', b'2'];
-pub const DRM_FORMAT_BGRX4444: [u8; 4] = [b'B', b'X', b'1', b'2'];
-pub const DRM_FORMAT_ARGB4444: [u8; 4] = [b'A', b'R', b'1', b'2'];
-pub const DRM_FORMAT_ABGR4444: [u8; 4] = [b'A', b'B', b'1', b'2'];
-pub const DRM_FORMAT_RGBA4444: [u8; 4] = [b'R', b'A', b'1', b'2'];
-pub const DRM_FORMAT_BGRA4444: [u8; 4] = [b'B', b'A', b'1', b'2'];
-pub const DRM_FORMAT_XRGB1555: [u8; 4] = [b'X', b'R', b'1', b'5'];
-pub const DRM_FORMAT_XBGR1555: [u8; 4] = [b'X', b'B', b'1', b'5'];
-pub const DRM_FORMAT_RGBX5551: [u8; 4] = [b'R', b'X', b'1', b'5'];
-pub const DRM_FORMAT_BGRX5551: [u8; 4] = [b'B', b'X', b'1', b'5'];
-pub const DRM_FORMAT_ARGB1555: [u8; 4] = [b'A', b'R', b'1', b'5'];
-pub const DRM_FORMAT_ABGR1555: [u8; 4] = [b'A', b'B', b'1', b'5'];
-pub const DRM_FORMAT_RGBA5551: [u8; 4] = [b'R', b'A', b'1', b'5'];
-pub const DRM_FORMAT_BGRA5551: [u8; 4] = [b'B', b'A', b'1', b'5'];
-pub const DRM_FORMAT_RGB565: [u8; 4] = [b'R', b'G', b'1', b'6'];
-pub const DRM_FORMAT_BGR565: [u8; 4] = [b'B', b'G', b'1', b'6'];
-pub const DRM_FORMAT_RGB888: [u8; 4] = [b'R', b'G', b'2', b'4'];
-pub const DRM_FORMAT_BGR888: [u8; 4] = [b'B', b'G', b'2', b'4'];
-pub const DRM_FORMAT_XRGB8888: [u8; 4] = [b'X', b'R', b'2', b'4'];
-pub const DRM_FORMAT_XBGR8888: [u8; 4] = [b'X', b'B', b'2', b'4'];
-pub const DRM_FORMAT_RGBX8888: [u8; 4] = [b'R', b'X', b'2', b'4'];
-pub const DRM_FORMAT_BGRX8888: [u8; 4] = [b'B', b'X', b'2', b'4'];
-pub const DRM_FORMAT_ARGB8888: [u8; 4] = [b'A', b'R', b'2', b'4'];
-pub const DRM_FORMAT_ABGR8888: [u8; 4] = [b'A', b'B', b'2', b'4'];
-pub const DRM_FORMAT_RGBA8888: [u8; 4] = [b'R', b'A', b'2', b'4'];
-pub const DRM_FORMAT_BGRA8888: [u8; 4] = [b'B', b'A', b'2', b'4'];
-pub const DRM_FORMAT_XRGB2101010: [u8; 4] = [b'X', b'R', b'3', b'0'];
-pub const DRM_FORMAT_XBGR2101010: [u8; 4] = [b'X', b'B', b'3', b'0'];
-pub const DRM_FORMAT_RGBX1010102: [u8; 4] = [b'R', b'X', b'3', b'0'];
-pub const DRM_FORMAT_BGRX1010102: [u8; 4] = [b'B', b'X', b'3', b'0'];
-pub const DRM_FORMAT_ARGB2101010: [u8; 4] = [b'A', b'R', b'3', b'0'];
-pub const DRM_FORMAT_ABGR2101010: [u8; 4] = [b'A', b'B', b'3', b'0'];
-pub const DRM_FORMAT_RGBA1010102: [u8; 4] = [b'R', b'A', b'3', b'0'];
-pub const DRM_FORMAT_BGRA1010102: [u8; 4] = [b'B', b'A', b'3', b'0'];
-pub const DRM_FORMAT_YUYV: [u8; 4] = [b'Y', b'U', b'Y', b'V'];
-pub const DRM_FORMAT_YVYU: [u8; 4] = [b'Y', b'V', b'Y', b'U'];
-pub const DRM_FORMAT_UYVY: [u8; 4] = [b'U', b'Y', b'V', b'Y'];
-pub const DRM_FORMAT_VYUY: [u8; 4] = [b'V', b'Y', b'U', b'Y'];
-pub const DRM_FORMAT_AYUV: [u8; 4] = [b'A', b'Y', b'U', b'V'];
-pub const DRM_FORMAT_NV12: [u8; 4] = [b'N', b'V', b'1', b'2'];
-pub const DRM_FORMAT_NV21: [u8; 4] = [b'N', b'V', b'2', b'1'];
-pub const DRM_FORMAT_NV16: [u8; 4] = [b'N', b'V', b'1', b'6'];
-pub const DRM_FORMAT_NV61: [u8; 4] = [b'N', b'V', b'6', b'1'];
-pub const DRM_FORMAT_NV24: [u8; 4] = [b'N', b'V', b'2', b'4'];
-pub const DRM_FORMAT_NV42: [u8; 4] = [b'N', b'V', b'4', b'2'];
-pub const DRM_FORMAT_YUV410: [u8; 4] = [b'Y', b'U', b'V', b'9'];
-pub const DRM_FORMAT_YVU410: [u8; 4] = [b'Y', b'V', b'U', b'9'];
-pub const DRM_FORMAT_YUV411: [u8; 4] = [b'Y', b'U', b'1', b'1'];
-pub const DRM_FORMAT_YVU411: [u8; 4] = [b'Y', b'V', b'1', b'1'];
-pub const DRM_FORMAT_YUV420: [u8; 4] = [b'Y', b'U', b'1', b'2'];
-pub const DRM_FORMAT_YVU420: [u8; 4] = [b'Y', b'V', b'1', b'2'];
-pub const DRM_FORMAT_YUV422: [u8; 4] = [b'Y', b'U', b'1', b'6'];
-pub const DRM_FORMAT_YVU422: [u8; 4] = [b'Y', b'V', b'1', b'6'];
-pub const DRM_FORMAT_YUV444: [u8; 4] = [b'Y', b'U', b'2', b'4'];
-pub const DRM_FORMAT_YVU444: [u8; 4] = [b'Y', b'V', b'2', b'4'];
diff --git a/gpu_buffer/src/lib.rs b/gpu_buffer/src/lib.rs
deleted file mode 100644
index dbae704..0000000
--- a/gpu_buffer/src/lib.rs
+++ /dev/null
@@ -1,543 +0,0 @@
-// 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(())
-//! # }
-//! ```
-
-pub mod drm_formats;
-mod raw;
-pub mod rendernode;
-
-use std::ffi::CStr;
-use std::fmt::{self, Display};
-use std::fs::File;
-use std::os::raw::c_char;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
-use std::rc::Rc;
-use std::result::Result;
-
-use data_model::VolatileMemoryError;
-
-use crate::drm_formats::*;
-use crate::raw::*;
-
-#[derive(Debug)]
-pub enum Error {
-    GbmFailed,
-    ExportFailed(base::Error),
-    MapFailed,
-    UnknownFormat(Format),
-    CheckedArithmetic {
-        field1: (&'static str, usize),
-        field2: (&'static str, usize),
-        op: &'static str,
-    },
-    InvalidPrecondition {
-        field1: (&'static str, usize),
-        field2: (&'static str, usize),
-        op: &'static str,
-    },
-    Memcopy(VolatileMemoryError),
-}
-
-impl Display for Error {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use self::Error::*;
-
-        match self {
-            GbmFailed => write!(f, "internal GBM failure"),
-            ExportFailed(e) => write!(f, "export failed: {}", e),
-            MapFailed => write!(f, "map failed"),
-            CheckedArithmetic {
-                field1: (label1, value1),
-                field2: (label2, value2),
-                op,
-            } => write!(
-                f,
-                "arithmetic failed: {}({}) {} {}({})",
-                label1, value1, op, label2, value2
-            ),
-            InvalidPrecondition {
-                field1: (label1, value1),
-                field2: (label2, value2),
-                op,
-            } => write!(
-                f,
-                "invalid precondition: {}({}) {} {}({})",
-                label1, value1, op, label2, value2
-            ),
-            UnknownFormat(format) => write!(f, "unknown format {:?}", format),
-            Memcopy(e) => write!(f, "error copying memory: {}", e),
-        }
-    }
-}
-
-/// 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]
-    }
-
-    /// Returns the number of bytes per pixel for the given plane, suitable for making copies
-    /// to/from the plane.
-    pub fn bytes_per_pixel(&self, plane: usize) -> Option<usize> {
-        let b = self.to_bytes();
-
-        // NV12 and NV21 have 2 planes with 1 byte per pixel.
-        if (b == DRM_FORMAT_NV12 || b == DRM_FORMAT_NV21) && plane < 2 {
-            return Some(1);
-        }
-
-        // YVU420 has 3 planes, all with the same 1 byte per pixel.
-        if b == DRM_FORMAT_YVU420 && plane < 3 {
-            return Some(1);
-        }
-
-        if plane != 0 {
-            return None;
-        }
-
-        let bpp = match self.to_bytes() {
-            DRM_FORMAT_BGR233 => 1,
-            DRM_FORMAT_C8 => 1,
-            DRM_FORMAT_R8 => 1,
-            DRM_FORMAT_RGB332 => 1,
-            DRM_FORMAT_ABGR1555 => 2,
-            DRM_FORMAT_ABGR4444 => 2,
-            DRM_FORMAT_ARGB1555 => 2,
-            DRM_FORMAT_ARGB4444 => 2,
-            DRM_FORMAT_BGR565 => 2,
-            DRM_FORMAT_BGRA4444 => 2,
-            DRM_FORMAT_BGRA5551 => 2,
-            DRM_FORMAT_BGRX4444 => 2,
-            DRM_FORMAT_BGRX5551 => 2,
-            DRM_FORMAT_GR88 => 2,
-            DRM_FORMAT_RG88 => 2,
-            DRM_FORMAT_RGB565 => 2,
-            DRM_FORMAT_RGBA4444 => 2,
-            DRM_FORMAT_RGBA5551 => 2,
-            DRM_FORMAT_RGBX4444 => 2,
-            DRM_FORMAT_RGBX5551 => 2,
-            DRM_FORMAT_UYVY => 2,
-            DRM_FORMAT_VYUY => 2,
-            DRM_FORMAT_XBGR1555 => 2,
-            DRM_FORMAT_XBGR4444 => 2,
-            DRM_FORMAT_XRGB1555 => 2,
-            DRM_FORMAT_XRGB4444 => 2,
-            DRM_FORMAT_YUYV => 2,
-            DRM_FORMAT_YVYU => 2,
-            DRM_FORMAT_BGR888 => 3,
-            DRM_FORMAT_RGB888 => 3,
-            DRM_FORMAT_ABGR2101010 => 4,
-            DRM_FORMAT_ABGR8888 => 4,
-            DRM_FORMAT_ARGB2101010 => 4,
-            DRM_FORMAT_ARGB8888 => 4,
-            DRM_FORMAT_AYUV => 4,
-            DRM_FORMAT_BGRA1010102 => 4,
-            DRM_FORMAT_BGRA8888 => 4,
-            DRM_FORMAT_BGRX1010102 => 4,
-            DRM_FORMAT_BGRX8888 => 4,
-            DRM_FORMAT_RGBA1010102 => 4,
-            DRM_FORMAT_RGBA8888 => 4,
-            DRM_FORMAT_RGBX1010102 => 4,
-            DRM_FORMAT_RGBX8888 => 4,
-            DRM_FORMAT_XBGR2101010 => 4,
-            DRM_FORMAT_XBGR8888 => 4,
-            DRM_FORMAT_XRGB2101010 => 4,
-            DRM_FORMAT_XRGB8888 => 4,
-            _ => return None,
-        };
-        Some(bpp)
-    }
-}
-
-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 })))
-        }
-    }
-
-    /// Copies and returns name of GBM backend.
-    pub fn get_backend_name(&self) -> String {
-        let backend_name: *const c_char = unsafe { gbm_device_get_backend_name(self.0.gbm) };
-        let c_str: &CStr = unsafe { CStr::from_ptr(backend_name) };
-        let str_slice: &str = c_str.to_str().unwrap_or("");
-        str_slice.to_owned()
-    }
-
-    /// Creates a new buffer with the given metadata.
-    pub fn create_buffer(
-        &self,
-        width: u32,
-        height: u32,
-        format: Format,
-        usage: Flags,
-    ) -> Result<Buffer, Error> {
-        // 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(Error::GbmFailed)
-        } 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) }
-    }
-
-    /// `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_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_plane_count(self.0) as usize }
-    }
-
-    /// Handle as u64 for the given plane.
-    pub fn plane_handle(&self, plane: usize) -> u64 {
-        // This is always safe to call with a valid gbm_bo pointer.
-        unsafe { gbm_bo_get_handle_for_plane(self.0, plane).u64 }
-    }
-
-    /// Offset in bytes for the given plane.
-    pub fn plane_offset(&self, plane: usize) -> u32 {
-        // This is always safe to call with a valid gbm_bo pointer.
-        unsafe { gbm_bo_get_offset(self.0, plane) }
-    }
-
-    /// Length in bytes of one row for the given plane.
-    pub fn plane_stride(&self, plane: usize) -> u32 {
-        // This is always safe to call with a valid gbm_bo pointer.
-        unsafe { gbm_bo_get_stride_for_plane(self.0, plane) }
-    }
-
-    /// Size of a plane, in bytes.
-    pub fn plane_size(&self, plane: usize) -> u32 {
-        // This is always safe to call with a valid gbm_bo pointer.
-        unsafe { gbm_bo_get_plane_size(self.0, plane) }
-    }
-
-    /// 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),
-        }
-    }
-}
-
-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;
-
-    #[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]
-    fn format_bytes_per_pixel() {
-        let f = Format::new(b'X', b'R', b'2', b'4');
-        assert_eq!(f.bytes_per_pixel(0), Some(4));
-        assert_eq!(f.bytes_per_pixel(1), None);
-        let f = Format::new(b'N', b'V', b'1', b'2');
-        assert_eq!(f.bytes_per_pixel(0), Some(1));
-        assert_eq!(f.bytes_per_pixel(1), Some(1));
-        assert_eq!(f.bytes_per_pixel(2), None);
-        let f = Format::new(b'R', b'8', b' ', b' ');
-        assert_eq!(f.bytes_per_pixel(0), Some(1));
-        assert_eq!(f.bytes_per_pixel(1), None);
-        let f = Format::new(b'B', b'G', b'2', b'4');
-        assert_eq!(f.bytes_per_pixel(0), Some(3));
-        assert_eq!(f.bytes_per_pixel(1), None);
-        let f = Format::new(b'G', b'R', b'8', b'8');
-        assert_eq!(f.bytes_per_pixel(0), Some(2));
-        assert_eq!(f.bytes_per_pixel(1), None);
-        let f = Format::new(b'Z', b'A', b'C', b'H');
-        assert_eq!(f.bytes_per_pixel(0), None);
-    }
-
-    #[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");
-    }
-}
diff --git a/resources/Cargo.toml b/resources/Cargo.toml
index 98850d4..041da9f 100644
--- a/resources/Cargo.toml
+++ b/resources/Cargo.toml
@@ -4,11 +4,7 @@
 authors = ["The Chromium OS Authors"]
 edition = "2018"
 
-[features]
-wl-dmabuf = ["gpu_buffer"]
-
 [dependencies]
-gpu_buffer = { path = "../gpu_buffer", optional = true }
 libc = "*"
 msg_socket = { path = "../msg_socket" }
 base = { path = "../base" }
diff --git a/resources/src/gpu_allocator.rs b/resources/src/gpu_allocator.rs
deleted file mode 100644
index 70c0752..0000000
--- a/resources/src/gpu_allocator.rs
+++ /dev/null
@@ -1,122 +0,0 @@
-// 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;
-
-use base::RawDescriptor;
-#[cfg(feature = "wl-dmabuf")]
-use libc::EINVAL;
-
-use msg_socket::MsgOnSocket;
-
-#[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)
-        -> base::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,
-    ) -> base::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(base::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(base::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<dyn 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)
-}
diff --git a/resources/src/lib.rs b/resources/src/lib.rs
index 97943d0..0a25181 100644
--- a/resources/src/lib.rs
+++ b/resources/src/lib.rs
@@ -5,8 +5,6 @@
 //! Manages system resources that can be allocated to VMs and their devices.
 
 extern crate base;
-#[cfg(feature = "wl-dmabuf")]
-extern crate gpu_buffer;
 extern crate libc;
 extern crate msg_socket;
 
@@ -15,13 +13,9 @@
 use std::fmt::Display;
 
 pub use crate::address_allocator::AddressAllocator;
-pub use crate::gpu_allocator::{
-    GpuAllocatorError, GpuMemoryAllocator, GpuMemoryDesc, GpuMemoryPlaneDesc,
-};
 pub use crate::system_allocator::{MmioType, SystemAllocator};
 
 mod address_allocator;
-mod gpu_allocator;
 mod system_allocator;
 
 /// Used to tag SystemAllocator allocations.
@@ -45,7 +39,6 @@
 pub enum Error {
     AllocSizeZero,
     BadAlignment,
-    CreateGpuAllocator(GpuAllocatorError),
     ExistingAlloc(Alloc),
     InvalidAlloc(Alloc),
     MissingHighMMIOAddresses,
@@ -67,7 +60,6 @@
         match self {
             AllocSizeZero => write!(f, "Allocation cannot have size of 0"),
             BadAlignment => write!(f, "Pool alignment must be a power of 2"),
-            CreateGpuAllocator(e) => write!(f, "Failed to create GPU allocator: {:?}", e),
             ExistingAlloc(tag) => write!(f, "Alloc already exists: {:?}", tag),
             InvalidAlloc(tag) => write!(f, "Invalid Alloc: {:?}", tag),
             MissingHighMMIOAddresses => write!(f, "High MMIO address range not specified"),
diff --git a/resources/src/system_allocator.rs b/resources/src/system_allocator.rs
index 82a89c2..ad5ef7d 100644
--- a/resources/src/system_allocator.rs
+++ b/resources/src/system_allocator.rs
@@ -5,7 +5,6 @@
 use base::pagesize;
 
 use crate::address_allocator::{AddressAllocator, AddressAllocatorSet};
-use crate::gpu_allocator::{self, GpuMemoryAllocator};
 use crate::{Alloc, Error, Result};
 
 /// Manages allocating system resources such as address space and interrupt numbers.
@@ -18,7 +17,7 @@
 ///           .add_io_addresses(0x1000, 0x10000)
 ///           .add_high_mmio_addresses(0x10000000, 0x10000000)
 ///           .add_low_mmio_addresses(0x30000000, 0x10000)
-///           .create_allocator(5, false) {
+///           .create_allocator(5) {
 ///       assert_eq!(a.allocate_irq(), Some(5));
 ///       assert_eq!(a.allocate_irq(), Some(6));
 ///       assert_eq!(
@@ -53,7 +52,6 @@
     // Indexed by MmioType::Low and MmioType::High.
     mmio_address_spaces: [AddressAllocator; 2],
 
-    gpu_allocator: Option<Box<dyn GpuMemoryAllocator>>,
     next_irq: u32,
     next_anon_id: usize,
 }
@@ -69,7 +67,6 @@
     /// * `high_size` - The size of high MMIO space.
     /// * `low_base` - The starting address of low MMIO space.
     /// * `low_size` - The size of low 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>,
@@ -78,7 +75,6 @@
         high_size: u64,
         low_base: u64,
         low_size: u64,
-        create_gpu_allocator: bool,
         first_irq: u32,
     ) -> Result<Self> {
         let page_size = pagesize() as u64;
@@ -94,11 +90,6 @@
                 // MmioType::High
                 AddressAllocator::new(high_base, high_size, Some(page_size))?,
             ],
-            gpu_allocator: if create_gpu_allocator {
-                gpu_allocator::create_gpu_memory_allocator().map_err(Error::CreateGpuAllocator)?
-            } else {
-                None
-            },
             next_irq: first_irq,
             next_anon_id: 0,
         })
@@ -137,11 +128,6 @@
         AddressAllocatorSet::new(&mut self.mmio_address_spaces)
     }
 
-    /// Gets an allocator to be used for GPU memory.
-    pub fn gpu_memory_allocator(&self) -> Option<&dyn GpuMemoryAllocator> {
-        self.gpu_allocator.as_ref().map(|v| v.as_ref())
-    }
-
     /// Gets a unique anonymous allocation
     pub fn get_anon_alloc(&mut self) -> Alloc {
         self.next_anon_id += 1;
@@ -189,11 +175,7 @@
         self
     }
 
-    pub fn create_allocator(
-        &self,
-        first_irq: u32,
-        gpu_allocation: bool,
-    ) -> Result<SystemAllocator> {
+    pub fn create_allocator(&self, first_irq: u32) -> Result<SystemAllocator> {
         SystemAllocator::new(
             self.io_base,
             self.io_size,
@@ -201,7 +183,6 @@
             self.high_mmio_size.ok_or(Error::MissingHighMMIOAddresses)?,
             self.low_mmio_base.ok_or(Error::MissingLowMMIOAddresses)?,
             self.low_mmio_size.ok_or(Error::MissingLowMMIOAddresses)?,
-            gpu_allocation,
             first_irq,
         )
     }
diff --git a/rutabaga_gfx/Cargo.toml b/rutabaga_gfx/Cargo.toml
index 14aed81..4a018fa 100644
--- a/rutabaga_gfx/Cargo.toml
+++ b/rutabaga_gfx/Cargo.toml
@@ -8,8 +8,13 @@
 gfxstream = []
 virgl_renderer = []
 virgl_renderer_next = []
+minigbm = []
+# To try out Vulkano, delete the following line and uncomment the line in "dependencies".  vulkano
+# features are just a prototype and not integrated yet into the ChromeOS build system.
+vulkano = []
 
 [dependencies]
 data_model = { path = "../data_model" }
 libc = "*"
 base = { path = "../base" }
+#vulkano = {git = "https:/github.com/vulkano-rs/vulkano.git", optional = true}
diff --git a/rutabaga_gfx/src/gfxstream.rs b/rutabaga_gfx/src/gfxstream.rs
index 3da76b4..8617257 100644
--- a/rutabaga_gfx/src/gfxstream.rs
+++ b/rutabaga_gfx/src/gfxstream.rs
@@ -2,7 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-//! virgl_renderer: Handles 3D virtio-gpu hypercalls using gfxstream.
+//! gfxstream: Handles 3D virtio-gpu hypercalls using gfxstream.
+//!
 //! External code found at https://android.googlesource.com/device/generic/vulkan-cereal/.
 
 #![cfg(feature = "gfxstream")]
diff --git a/rutabaga_gfx/src/lib.rs b/rutabaga_gfx/src/lib.rs
index 2b661b8..5813d54 100644
--- a/rutabaga_gfx/src/lib.rs
+++ b/rutabaga_gfx/src/lib.rs
@@ -2,15 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-//! A crate for handling 2D and 3D virtio-gpu hypercalls.
+//! A crate for handling 2D and 3D virtio-gpu hypercalls, along with graphics
+//! swapchain allocation and mapping.
 
 mod generated;
 mod gfxstream;
+#[macro_use]
+mod macros;
 mod renderer_utils;
 mod rutabaga_2d;
 mod rutabaga_core;
+mod rutabaga_gralloc;
 mod rutabaga_utils;
 mod virgl_renderer;
 
 pub use crate::rutabaga_core::{Rutabaga, RutabagaBuilder};
+pub use crate::rutabaga_gralloc::{
+    DrmFormat, ImageAllocationInfo, ImageMemoryRequirements, RutabagaGralloc, RutabagaGrallocFlags,
+};
 pub use crate::rutabaga_utils::*;
diff --git a/rutabaga_gfx/src/macros.rs b/rutabaga_gfx/src/macros.rs
new file mode 100644
index 0000000..24577b7
--- /dev/null
+++ b/rutabaga_gfx/src/macros.rs
@@ -0,0 +1,45 @@
+// Copyright 2021 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.
+
+//! Macros for rutabaga_gfx.
+
+#[macro_export]
+macro_rules! checked_range {
+    ($x:expr; <= $y:expr) => {
+        if $x <= $y {
+            Ok(())
+        } else {
+            Err(RutabagaError::CheckedRange {
+                field1: (stringify!($x), $x as usize),
+                field2: (stringify!($y), $y as usize),
+            })
+        }
+    };
+    ($x:ident <= $y:ident) => {
+        check_range!($x; <= $y)
+    };
+}
+
+#[macro_export]
+macro_rules! checked_arithmetic {
+    ($x:ident $op:ident $y:ident $op_name:expr) => {
+        $x.$op($y).ok_or_else(|| RutabagaError::CheckedArithmetic {
+            field1: (stringify!($x), $x as usize),
+            field2: (stringify!($y), $y as usize),
+            op: $op_name,
+        })
+    };
+    ($x:ident + $y:ident) => {
+        checked_arithmetic!($x checked_add $y "+")
+    };
+    ($x:ident - $y:ident) => {
+        checked_arithmetic!($x checked_sub $y "-")
+    };
+    ($x:ident * $y:ident) => {
+        checked_arithmetic!($x checked_mul $y "*")
+    };
+    ($x:ident / $y:ident) => {
+        checked_arithmetic!($x checked_div $y "/")
+    };
+}
diff --git a/rutabaga_gfx/src/renderer_utils.rs b/rutabaga_gfx/src/renderer_utils.rs
index 1b54640..9b37264 100644
--- a/rutabaga_gfx/src/renderer_utils.rs
+++ b/rutabaga_gfx/src/renderer_utils.rs
@@ -44,7 +44,7 @@
 pub fn ret_to_res(ret: i32) -> RutabagaResult<()> {
     match ret {
         0 => Ok(()),
-        _ => Err(RutabagaError::RutabagaComponentError(ret)),
+        _ => Err(RutabagaError::ComponentError(ret)),
     }
 }
 
diff --git a/rutabaga_gfx/src/rutabaga_2d.rs b/rutabaga_gfx/src/rutabaga_2d.rs
index 78ecf9e..ac33435 100644
--- a/rutabaga_gfx/src/rutabaga_2d.rs
+++ b/rutabaga_gfx/src/rutabaga_2d.rs
@@ -11,41 +11,6 @@
 use crate::rutabaga_core::{Rutabaga2DInfo, RutabagaComponent, RutabagaResource};
 use crate::rutabaga_utils::*;
 
-macro_rules! checked_arithmetic {
-    ($x:ident $op:ident $y:ident $op_name:expr) => {
-        $x.$op($y).ok_or_else(|| RutabagaError::CheckedArithmetic {
-            field1: (stringify!($x), $x as usize),
-            field2: (stringify!($y), $y as usize),
-            op: $op_name,
-        })
-    };
-    ($x:ident + $y:ident) => {
-        checked_arithmetic!($x checked_add $y "+")
-    };
-    ($x:ident - $y:ident) => {
-        checked_arithmetic!($x checked_sub $y "-")
-    };
-    ($x:ident * $y:ident) => {
-        checked_arithmetic!($x checked_mul $y "*")
-    };
-}
-
-macro_rules! checked_range {
-    ($x:expr; <= $y:expr) => {
-        if $x <= $y {
-            Ok(())
-        } else {
-            Err(RutabagaError::CheckedRange {
-                field1: (stringify!($x), $x as usize),
-                field2: (stringify!($y), $y as usize),
-            })
-        }
-    };
-    ($x:ident <= $y:ident) => {
-        check_range!($x; <= $y)
-    };
-}
-
 /// Transfers a resource from potentially many chunked src VolatileSlices to a dst VolatileSlice.
 pub fn transfer_2d<'a, S: Iterator<Item = VolatileSlice<'a>>>(
     resource_w: u32,
diff --git a/rutabaga_gfx/src/rutabaga_core.rs b/rutabaga_gfx/src/rutabaga_core.rs
index f6e46e3..6ffa31d 100644
--- a/rutabaga_gfx/src/rutabaga_core.rs
+++ b/rutabaga_gfx/src/rutabaga_core.rs
@@ -245,7 +245,7 @@
         let component = self
             .components
             .get(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         let (capset_version, capset_size) = component.get_capset_info(capset_id);
         Ok((capset_id, capset_version, capset_size))
@@ -263,7 +263,7 @@
         let component = self
             .components
             .get(&component_type)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         Ok(component.get_capset(capset_id, version))
     }
@@ -290,7 +290,7 @@
             let component = self
                 .components
                 .get_mut(&self.default_component)
-                .ok_or(RutabagaError::Unsupported)?;
+                .ok_or(RutabagaError::InvalidComponent)?;
 
             component.create_fence(fence_data)?;
         }
@@ -335,7 +335,7 @@
         let component = self
             .components
             .get_mut(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         if self.resources.contains_key(&resource_id) {
             return Err(RutabagaError::InvalidResourceId);
@@ -357,7 +357,7 @@
         let component = self
             .components
             .get_mut(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         let resource = self
             .resources
@@ -374,7 +374,7 @@
         let component = self
             .components
             .get_mut(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         let resource = self
             .resources
@@ -391,7 +391,7 @@
         let component = self
             .components
             .get_mut(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         self.resources
             .remove(&resource_id)
@@ -412,7 +412,7 @@
         let component = self
             .components
             .get(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         let resource = self
             .resources
@@ -436,7 +436,7 @@
         let component = self
             .components
             .get(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         let resource = self
             .resources
@@ -458,7 +458,7 @@
         let component = self
             .components
             .get_mut(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         if self.resources.contains_key(&resource_id) {
             return Err(RutabagaError::InvalidResourceId);
@@ -477,7 +477,7 @@
         let component = self
             .components
             .get(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         if !self.resources.contains_key(&resource_id) {
             return Err(RutabagaError::InvalidResourceId);
@@ -492,7 +492,7 @@
         let component = self
             .components
             .get(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         if !self.resources.contains_key(&resource_id) {
             return Err(RutabagaError::InvalidResourceId);
@@ -506,7 +506,7 @@
         let component = self
             .components
             .get(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         if !self.resources.contains_key(&resource_id) {
             return Err(RutabagaError::InvalidResourceId);
@@ -536,7 +536,7 @@
             }
             (Some(handle), false) => {
                 // Exactly one strong reference in this case.
-                let hnd = Arc::try_unwrap(handle).map_err(|_| RutabagaError::Unsupported)?;
+                let hnd = Arc::try_unwrap(handle).map_err(|_| RutabagaError::SpecViolation)?;
                 Ok(hnd)
             }
             _ => Err(RutabagaError::Unsupported),
@@ -548,7 +548,7 @@
         let component = self
             .components
             .get(&self.default_component)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         component.export_fence(fence_id)
     }
@@ -565,7 +565,7 @@
         let component = self
             .components
             .get_mut(&component_type)
-            .ok_or(RutabagaError::Unsupported)?;
+            .ok_or(RutabagaError::InvalidComponent)?;
 
         if self.contexts.contains_key(&ctx_id) {
             return Err(RutabagaError::InvalidContextId);
diff --git a/gpu_buffer/Cargo.toml b/rutabaga_gfx/src/rutabaga_gralloc/Cargo.toml
similarity index 100%
rename from gpu_buffer/Cargo.toml
rename to rutabaga_gfx/src/rutabaga_gralloc/Cargo.toml
diff --git a/rutabaga_gfx/src/rutabaga_gralloc/formats.rs b/rutabaga_gfx/src/rutabaga_gralloc/formats.rs
new file mode 100644
index 0000000..31abfcf
--- /dev/null
+++ b/rutabaga_gfx/src/rutabaga_gralloc/formats.rs
@@ -0,0 +1,374 @@
+// Copyright 2021 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.
+
+//! formats: Utility file for dealing with DRM and VK formats, and canonical
+//! size calculations.
+
+use std::fmt;
+
+use crate::checked_arithmetic;
+use crate::rutabaga_gralloc::gralloc::{ImageAllocationInfo, ImageMemoryRequirements};
+use crate::rutabaga_utils::*;
+
+#[cfg(feature = "vulkano")]
+use vulkano::format::Format as VulkanFormat;
+
+#[cfg(feature = "vulkano")]
+use vulkano::image::ImageAspect as VulkanImageAspect;
+
+/*
+ * This list is based on Sommelier / cros_gralloc guest userspace.  Formats that are never
+ * used by guest userspace (i.e, DRM_FORMAT_RGB332) are left out for simplicity.
+ */
+
+pub const DRM_FORMAT_R8: [u8; 4] = [b'R', b'8', b' ', b' '];
+
+pub const DRM_FORMAT_RGB565: [u8; 4] = [b'R', b'G', b'1', b'6'];
+pub const DRM_FORMAT_BGR888: [u8; 4] = [b'B', b'G', b'2', b'4'];
+
+pub const DRM_FORMAT_XRGB8888: [u8; 4] = [b'X', b'R', b'2', b'4'];
+pub const DRM_FORMAT_XBGR8888: [u8; 4] = [b'X', b'B', b'2', b'4'];
+
+pub const DRM_FORMAT_ARGB8888: [u8; 4] = [b'A', b'R', b'2', b'4'];
+pub const DRM_FORMAT_ABGR8888: [u8; 4] = [b'A', b'B', b'2', b'4'];
+
+pub const DRM_FORMAT_XRGB2101010: [u8; 4] = [b'X', b'R', b'3', b'0'];
+pub const DRM_FORMAT_XBGR2101010: [u8; 4] = [b'X', b'B', b'3', b'0'];
+pub const DRM_FORMAT_ARGB2101010: [u8; 4] = [b'A', b'R', b'3', b'0'];
+pub const DRM_FORMAT_ABGR2101010: [u8; 4] = [b'A', b'B', b'3', b'0'];
+
+pub const DRM_FORMAT_ABGR16161616F: [u8; 4] = [b'A', b'B', b'4', b'H'];
+
+pub const DRM_FORMAT_NV12: [u8; 4] = [b'N', b'V', b'1', b'2'];
+pub const DRM_FORMAT_YVU420: [u8; 4] = [b'Y', b'V', b'1', b'2'];
+
+/// A [fourcc](https://en.wikipedia.org/wiki/FourCC) format identifier.
+#[derive(Copy, Clone, Eq, PartialEq, Default)]
+pub struct DrmFormat(pub u32);
+
+/// Planar properties associated with each `DrmFormat`.  Copied from helpers.c in minigbm.
+#[derive(Copy, Clone)]
+pub struct PlanarLayout {
+    pub num_planes: usize,
+    horizontal_subsampling: [u32; 3],
+    vertical_subsampling: [u32; 3],
+    bytes_per_pixel: [u32; 3],
+}
+
+static PACKED_1BPP: PlanarLayout = PlanarLayout {
+    num_planes: 1,
+    horizontal_subsampling: [1, 0, 0],
+    vertical_subsampling: [1, 0, 0],
+    bytes_per_pixel: [1, 0, 0],
+};
+
+static PACKED_2BPP: PlanarLayout = PlanarLayout {
+    num_planes: 1,
+    horizontal_subsampling: [1, 0, 0],
+    vertical_subsampling: [1, 0, 0],
+    bytes_per_pixel: [2, 0, 0],
+};
+
+static PACKED_3BPP: PlanarLayout = PlanarLayout {
+    num_planes: 1,
+    horizontal_subsampling: [1, 0, 0],
+    vertical_subsampling: [1, 0, 0],
+    bytes_per_pixel: [3, 0, 0],
+};
+
+static PACKED_4BPP: PlanarLayout = PlanarLayout {
+    num_planes: 1,
+    horizontal_subsampling: [1, 0, 0],
+    vertical_subsampling: [1, 0, 0],
+    bytes_per_pixel: [4, 0, 0],
+};
+
+static PACKED_8BPP: PlanarLayout = PlanarLayout {
+    num_planes: 1,
+    horizontal_subsampling: [1, 0, 0],
+    vertical_subsampling: [1, 0, 0],
+    bytes_per_pixel: [8, 0, 0],
+};
+
+static BIPLANAR_YUV420: PlanarLayout = PlanarLayout {
+    num_planes: 2,
+    horizontal_subsampling: [1, 2, 0],
+    vertical_subsampling: [1, 2, 0],
+    bytes_per_pixel: [1, 2, 0],
+};
+
+static TRIPLANAR_YUV420: PlanarLayout = PlanarLayout {
+    num_planes: 3,
+    horizontal_subsampling: [1, 2, 2],
+    vertical_subsampling: [1, 2, 2],
+    bytes_per_pixel: [1, 1, 1],
+};
+
+impl DrmFormat {
+    /// Constructs a format identifer using a fourcc byte sequence.
+    #[inline(always)]
+    pub fn new(a: u8, b: u8, c: u8, d: u8) -> DrmFormat {
+        DrmFormat(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]
+    }
+
+    /// Returns the planar layout of the format.
+    pub fn planar_layout(&self) -> RutabagaResult<PlanarLayout> {
+        match self.to_bytes() {
+            DRM_FORMAT_R8 => Ok(PACKED_1BPP),
+            DRM_FORMAT_RGB565 => Ok(PACKED_2BPP),
+            DRM_FORMAT_BGR888 => Ok(PACKED_3BPP),
+            DRM_FORMAT_ABGR2101010
+            | DRM_FORMAT_ABGR8888
+            | DRM_FORMAT_XBGR2101010
+            | DRM_FORMAT_XBGR8888
+            | DRM_FORMAT_ARGB2101010
+            | DRM_FORMAT_ARGB8888
+            | DRM_FORMAT_XRGB2101010
+            | DRM_FORMAT_XRGB8888 => Ok(PACKED_4BPP),
+            DRM_FORMAT_ABGR16161616F => Ok(PACKED_8BPP),
+            DRM_FORMAT_NV12 => Ok(BIPLANAR_YUV420),
+            DRM_FORMAT_YVU420 => Ok(TRIPLANAR_YUV420),
+            _ => Err(RutabagaError::Unsupported),
+        }
+    }
+
+    #[cfg(feature = "vulkano")]
+    /// Returns the Vulkan format from the DrmFormat.
+    pub fn vulkan_format(&self) -> RutabagaResult<VulkanFormat> {
+        match self.to_bytes() {
+            DRM_FORMAT_R8 => Ok(VulkanFormat::R8Unorm),
+            DRM_FORMAT_RGB565 => Ok(VulkanFormat::R5G6B5UnormPack16),
+            DRM_FORMAT_BGR888 => Ok(VulkanFormat::R8G8B8Unorm),
+            DRM_FORMAT_ABGR2101010 | DRM_FORMAT_XBGR2101010 => {
+                Ok(VulkanFormat::A2R10G10B10UnormPack32)
+            }
+            DRM_FORMAT_ABGR8888 | DRM_FORMAT_XBGR8888 => Ok(VulkanFormat::R8G8B8A8Unorm),
+            DRM_FORMAT_ARGB2101010 | DRM_FORMAT_XRGB2101010 => {
+                Ok(VulkanFormat::A2B10G10R10UnormPack32)
+            }
+            DRM_FORMAT_ARGB8888 | DRM_FORMAT_XRGB8888 => Ok(VulkanFormat::B8G8R8A8Unorm),
+            DRM_FORMAT_ABGR16161616F => Ok(VulkanFormat::R16G16B16A16Sfloat),
+            DRM_FORMAT_NV12 => Ok(VulkanFormat::G8B8R8_2PLANE420Unorm),
+            DRM_FORMAT_YVU420 => Ok(VulkanFormat::G8B8R8_3PLANE420Unorm),
+            _ => Err(RutabagaError::Unsupported),
+        }
+    }
+
+    #[cfg(feature = "vulkano")]
+    /// Returns the Vulkan format from the DrmFormat.
+    pub fn vulkan_image_aspect(&self, plane: usize) -> RutabagaResult<VulkanImageAspect> {
+        match self.to_bytes() {
+            DRM_FORMAT_R8
+            | DRM_FORMAT_RGB565
+            | DRM_FORMAT_BGR888
+            | DRM_FORMAT_ABGR2101010
+            | DRM_FORMAT_ABGR8888
+            | DRM_FORMAT_XBGR2101010
+            | DRM_FORMAT_XBGR8888
+            | DRM_FORMAT_ARGB2101010
+            | DRM_FORMAT_ARGB8888
+            | DRM_FORMAT_XRGB2101010
+            | DRM_FORMAT_XRGB8888 => Ok(VulkanImageAspect {
+                color: true,
+                ..VulkanImageAspect::none()
+            }),
+            DRM_FORMAT_NV12 => match plane {
+                0 => Ok(VulkanImageAspect {
+                    plane0: true,
+                    ..VulkanImageAspect::none()
+                }),
+                1 => Ok(VulkanImageAspect {
+                    plane1: true,
+                    ..VulkanImageAspect::none()
+                }),
+                _ => Err(RutabagaError::Unsupported),
+            },
+            DRM_FORMAT_YVU420 => match plane {
+                0 => Ok(VulkanImageAspect {
+                    plane0: true,
+                    ..VulkanImageAspect::none()
+                }),
+                1 => Ok(VulkanImageAspect {
+                    plane1: true,
+                    ..VulkanImageAspect::none()
+                }),
+                2 => Ok(VulkanImageAspect {
+                    plane2: true,
+                    ..VulkanImageAspect::none()
+                }),
+                _ => Err(RutabagaError::Unsupported),
+            },
+            _ => Err(RutabagaError::Unsupported),
+        }
+    }
+}
+
+impl From<u32> for DrmFormat {
+    fn from(u: u32) -> DrmFormat {
+        DrmFormat(u)
+    }
+}
+
+impl From<DrmFormat> for u32 {
+    fn from(f: DrmFormat) -> u32 {
+        f.0
+    }
+}
+
+impl fmt::Debug for DrmFormat {
+    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]
+            )
+        }
+    }
+}
+
+fn stride_from_layout(layout: &PlanarLayout, width: u32, plane: usize) -> RutabagaResult<u32> {
+    let bytes_per_pixel = layout.bytes_per_pixel[plane];
+    let horizontal_subsampling = layout.horizontal_subsampling[plane];
+    let subsampled_width = checked_arithmetic!(width / horizontal_subsampling)?;
+    let stride = checked_arithmetic!(bytes_per_pixel * subsampled_width)?;
+    Ok(stride)
+}
+
+pub fn canonical_image_requirements(
+    info: ImageAllocationInfo,
+) -> RutabagaResult<ImageMemoryRequirements> {
+    let mut image_requirements: ImageMemoryRequirements = Default::default();
+    let mut size: u32 = 0;
+    let layout = info.drm_format.planar_layout()?;
+    for plane in 0..layout.num_planes {
+        let plane_stride = stride_from_layout(&layout, info.width, plane)?;
+        image_requirements.strides[plane] = plane_stride;
+        if plane > 0 {
+            image_requirements.offsets[plane] = size as u32;
+        }
+
+        let height = info.height;
+        let vertical_subsampling = layout.vertical_subsampling[plane];
+        let subsampled_height = checked_arithmetic!(height / vertical_subsampling)?;
+        let plane_size = checked_arithmetic!(subsampled_height * plane_stride)?;
+        size = checked_arithmetic!(size + plane_size)?;
+    }
+
+    image_requirements.info = info;
+    image_requirements.size = size as u64;
+    Ok(image_requirements)
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use crate::rutabaga_gralloc::RutabagaGrallocFlags;
+    use std::fmt::Write;
+
+    #[test]
+    fn format_debug() {
+        let f = DrmFormat::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 = DrmFormat::new(0, 1, 2, 16);
+        let mut buf = String::new();
+        write!(&mut buf, "{:?}", f).unwrap();
+        assert_eq!(buf, "fourcc(0x00010210)");
+    }
+
+    #[test]
+    fn canonical_formats() {
+        let mut info = ImageAllocationInfo {
+            width: 10,
+            height: 10,
+            drm_format: DrmFormat::new(b'R', b'8', b' ', b' '),
+            flags: RutabagaGrallocFlags::empty(),
+        };
+
+        let r8_reqs = canonical_image_requirements(info).unwrap();
+
+        assert_eq!(r8_reqs.info.width, 10);
+        assert_eq!(r8_reqs.info.height, 10);
+        assert_eq!(r8_reqs.strides[0], 10);
+        assert_eq!(r8_reqs.strides[1], 0);
+        assert_eq!(r8_reqs.strides[2], 0);
+
+        assert_eq!(r8_reqs.offsets[0], 0);
+        assert_eq!(r8_reqs.offsets[1], 0);
+        assert_eq!(r8_reqs.offsets[2], 0);
+
+        assert_eq!(r8_reqs.size, 100);
+
+        info.drm_format = DrmFormat::new(b'X', b'R', b'2', b'4');
+        let xr24_reqs = canonical_image_requirements(info).unwrap();
+
+        assert_eq!(xr24_reqs.info.width, 10);
+        assert_eq!(xr24_reqs.info.height, 10);
+        assert_eq!(xr24_reqs.strides[0], 40);
+        assert_eq!(xr24_reqs.strides[1], 0);
+        assert_eq!(xr24_reqs.strides[2], 0);
+
+        assert_eq!(xr24_reqs.offsets[0], 0);
+        assert_eq!(xr24_reqs.offsets[1], 0);
+        assert_eq!(xr24_reqs.offsets[2], 0);
+
+        assert_eq!(xr24_reqs.size, 400);
+    }
+
+    #[test]
+    fn canonical_planar_formats() {
+        let mut info = ImageAllocationInfo {
+            width: 10,
+            height: 10,
+            drm_format: DrmFormat::new(b'N', b'V', b'1', b'2'),
+            flags: RutabagaGrallocFlags::empty(),
+        };
+
+        let nv12_reqs = canonical_image_requirements(info).unwrap();
+
+        assert_eq!(nv12_reqs.info.width, 10);
+        assert_eq!(nv12_reqs.info.height, 10);
+        assert_eq!(nv12_reqs.strides[0], 10);
+        assert_eq!(nv12_reqs.strides[1], 10);
+        assert_eq!(nv12_reqs.strides[2], 0);
+
+        assert_eq!(nv12_reqs.offsets[0], 0);
+        assert_eq!(nv12_reqs.offsets[1], 100);
+        assert_eq!(nv12_reqs.offsets[2], 0);
+
+        assert_eq!(nv12_reqs.size, 150);
+
+        info.drm_format = DrmFormat::new(b'Y', b'V', b'1', b'2');
+        let yv12_reqs = canonical_image_requirements(info).unwrap();
+
+        assert_eq!(yv12_reqs.info.width, 10);
+        assert_eq!(yv12_reqs.info.height, 10);
+        assert_eq!(yv12_reqs.strides[0], 10);
+        assert_eq!(yv12_reqs.strides[1], 5);
+        assert_eq!(yv12_reqs.strides[2], 5);
+
+        assert_eq!(yv12_reqs.offsets[0], 0);
+        assert_eq!(yv12_reqs.offsets[1], 100);
+        assert_eq!(yv12_reqs.offsets[2], 125);
+
+        assert_eq!(yv12_reqs.size, 150);
+    }
+}
diff --git a/rutabaga_gfx/src/rutabaga_gralloc/gralloc.rs b/rutabaga_gfx/src/rutabaga_gralloc/gralloc.rs
new file mode 100644
index 0000000..60847a5
--- /dev/null
+++ b/rutabaga_gfx/src/rutabaga_gralloc/gralloc.rs
@@ -0,0 +1,362 @@
+// Copyright 2021 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.
+
+//! gralloc: Cross-platform, Rust-based, Vulkan centric GPU allocation and
+//! mapping.
+
+use std::collections::BTreeMap as Map;
+
+use base::round_up_to_page_size;
+
+use crate::rutabaga_gralloc::formats::*;
+use crate::rutabaga_gralloc::system_gralloc::SystemGralloc;
+use crate::rutabaga_utils::*;
+
+#[cfg(feature = "minigbm")]
+use crate::rutabaga_gralloc::minigbm::MinigbmDevice;
+
+#[cfg(feature = "vulkano")]
+use crate::rutabaga_gralloc::vulkano_gralloc::VulkanoGralloc;
+
+/*
+ * Rutabaga gralloc flags are copied from minigbm, but redundant legacy flags are left out.
+ * For example, USE_WRITE / USE_CURSOR_64X64 / USE_CURSOR don't add much value.
+ */
+const RUTABAGA_GRALLOC_USE_SCANOUT: u32 = 1 << 0;
+const RUTABAGA_GRALLOC_USE_RENDERING: u32 = 1 << 2;
+const RUTABAGA_GRALLOC_USE_LINEAR: u32 = 1 << 4;
+const RUTABAGA_GRALLOC_USE_TEXTURING: u32 = 1 << 5;
+const RUTABAGA_GRALLOC_USE_CAMERA_WRITE: u32 = 1 << 6;
+const RUTABAGA_GRALLOC_USE_CAMERA_READ: u32 = 1 << 7;
+#[allow(dead_code)]
+const RUTABAGA_GRALLOC_USE_PROTECTED: u32 = 1 << 8;
+
+/* SW_{WRITE,READ}_RARELY omitted since not even Android uses this much. */
+const RUTABAGA_GRALLOC_USE_SW_READ_OFTEN: u32 = 1 << 9;
+const RUTABAGA_GRALLOC_USE_SW_WRITE_OFTEN: u32 = 1 << 11;
+
+#[allow(dead_code)]
+const RUTABAGA_GRALLOC_VIDEO_DECODER: u32 = 1 << 13;
+#[allow(dead_code)]
+const RUTABAGA_GRALLOC_VIDEO_ENCODER: u32 = 1 << 14;
+
+/// Usage flags for constructing a buffer object.
+#[derive(Copy, Clone, Eq, PartialEq, Default)]
+pub struct RutabagaGrallocFlags(pub u32);
+
+impl RutabagaGrallocFlags {
+    /// Returns empty set of flags.
+    #[inline(always)]
+    pub fn empty() -> RutabagaGrallocFlags {
+        RutabagaGrallocFlags(0)
+    }
+
+    /// Returns the given set of raw `RUTABAGA_GRALLOC` flags wrapped in a RutabagaGrallocFlags
+    /// struct.
+    #[inline(always)]
+    pub fn new(raw: u32) -> RutabagaGrallocFlags {
+        RutabagaGrallocFlags(raw)
+    }
+
+    /// Sets the scanout flag's presence.
+    #[inline(always)]
+    pub fn use_scanout(self, e: bool) -> RutabagaGrallocFlags {
+        if e {
+            RutabagaGrallocFlags(self.0 | RUTABAGA_GRALLOC_USE_SCANOUT)
+        } else {
+            RutabagaGrallocFlags(self.0 & !RUTABAGA_GRALLOC_USE_SCANOUT)
+        }
+    }
+
+    /// Sets the rendering flag's presence.
+    #[inline(always)]
+    pub fn use_rendering(self, e: bool) -> RutabagaGrallocFlags {
+        if e {
+            RutabagaGrallocFlags(self.0 | RUTABAGA_GRALLOC_USE_RENDERING)
+        } else {
+            RutabagaGrallocFlags(self.0 & !RUTABAGA_GRALLOC_USE_RENDERING)
+        }
+    }
+
+    /// Sets the linear flag's presence.
+    #[inline(always)]
+    pub fn use_linear(self, e: bool) -> RutabagaGrallocFlags {
+        if e {
+            RutabagaGrallocFlags(self.0 | RUTABAGA_GRALLOC_USE_LINEAR)
+        } else {
+            RutabagaGrallocFlags(self.0 & !RUTABAGA_GRALLOC_USE_LINEAR)
+        }
+    }
+
+    /// Returns true if the texturing flag is set.
+    #[inline(always)]
+    pub fn uses_texturing(self) -> bool {
+        self.0 & RUTABAGA_GRALLOC_USE_TEXTURING != 0
+    }
+
+    /// Returns true if the rendering flag is set.
+    #[inline(always)]
+    pub fn uses_rendering(self) -> bool {
+        self.0 & RUTABAGA_GRALLOC_USE_RENDERING != 0
+    }
+
+    /// Returns true if the memory will accessed by the CPU or an IP block that prefers host
+    /// visible allocations (i.e, camera).
+    #[inline(always)]
+    pub fn host_visible(self) -> bool {
+        self.0 & RUTABAGA_GRALLOC_USE_SW_READ_OFTEN != 0
+            || self.0 & RUTABAGA_GRALLOC_USE_SW_WRITE_OFTEN != 0
+            || self.0 & RUTABAGA_GRALLOC_USE_CAMERA_WRITE != 0
+            || self.0 & RUTABAGA_GRALLOC_USE_CAMERA_READ != 0
+    }
+
+    /// Returns true if the memory will read by the CPU or an IP block that prefers cached
+    /// allocations (i.e, camera).
+    #[inline(always)]
+    pub fn host_cached(self) -> bool {
+        self.0 & RUTABAGA_GRALLOC_USE_CAMERA_READ != 0
+            || self.0 & RUTABAGA_GRALLOC_USE_SW_READ_OFTEN != 0
+    }
+}
+
+/// Information required to allocate a swapchain image.
+#[derive(Copy, Clone, Default)]
+pub struct ImageAllocationInfo {
+    pub width: u32,
+    pub height: u32,
+    pub drm_format: DrmFormat,
+    pub flags: RutabagaGrallocFlags,
+}
+
+/// The memory requirements, compression and layout of a swapchain image.
+#[derive(Copy, Clone, Default)]
+pub struct ImageMemoryRequirements {
+    pub info: ImageAllocationInfo,
+    pub map_info: u32,
+    pub strides: [u32; 4],
+    pub offsets: [u32; 4],
+    pub modifier: u64,
+    pub size: u64,
+    pub vulkan_info: Option<VulkanInfo>,
+}
+
+/// Trait that needs to be implemented to service graphics memory requests.  Two step allocation
+/// process:
+///
+///   (1) Get memory requirements for a given allocation request.
+///   (2) Allocate using those requirements.
+pub trait Gralloc {
+    /// This function must return true if the implementation can:
+    ///
+    ///   (1) allocate GPU memory and
+    ///   (2) {export to}/{import from} into a OS-specific RutabagaHandle.
+    fn supports_external_gpu_memory(&self) -> bool;
+
+    /// This function must return true the implementation can {export to}/{import from} a Linux
+    /// dma-buf.  This often used for sharing with the scanout engine or multimedia subsystems.
+    fn supports_dmabuf(&self) -> bool;
+
+    /// Implementations must return the resource layout, compression, and caching properties of
+    /// an allocation request.
+    fn get_image_memory_requirements(
+        &mut self,
+        info: ImageAllocationInfo,
+    ) -> RutabagaResult<ImageMemoryRequirements>;
+
+    /// Implementations must allocate memory given the requirements and return a RutabagaHandle
+    /// upon success.
+    fn allocate_memory(&mut self, reqs: ImageMemoryRequirements) -> RutabagaResult<RutabagaHandle>;
+}
+
+/// Enumeration of possible allocation backends.
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord)]
+pub enum GrallocBackend {
+    #[allow(dead_code)]
+    Vulkano,
+    #[allow(dead_code)]
+    Minigbm,
+    System,
+}
+
+/// A container for a variety of allocation backends.
+pub struct RutabagaGralloc {
+    grallocs: Map<GrallocBackend, Box<dyn Gralloc>>,
+}
+
+impl RutabagaGralloc {
+    /// Returns a new RutabagaGralloc instance upon success.  All allocation backends that have
+    /// been built are initialized.  The default system allocator is always initialized.
+    pub fn new() -> RutabagaResult<RutabagaGralloc> {
+        let mut grallocs: Map<GrallocBackend, Box<dyn Gralloc>> = Default::default();
+
+        let system = SystemGralloc::init()?;
+        grallocs.insert(GrallocBackend::System, system);
+
+        #[cfg(feature = "minigbm")]
+        {
+            // crosvm integration tests build with the "wl-dmabuf" feature, which translates in
+            // rutabaga to the "minigbm" feature.  These tests run on hosts where a rendernode is
+            // not present, and minigbm can not be initialized.
+            //
+            // Thus, to keep kokoro happy, allow minigbm initialization to fail silently for now.
+            if let Ok(gbm_device) = MinigbmDevice::init() {
+                grallocs.insert(GrallocBackend::Minigbm, gbm_device);
+            }
+        }
+
+        #[cfg(feature = "vulkano")]
+        {
+            let vulkano = VulkanoGralloc::init()?;
+            grallocs.insert(GrallocBackend::Vulkano, vulkano);
+        }
+
+        Ok(RutabagaGralloc { grallocs })
+    }
+
+    /// Returns true if one of the allocation backends supports GPU external memory.
+    pub fn supports_external_gpu_memory(&self) -> bool {
+        for gralloc in self.grallocs.values() {
+            if gralloc.supports_external_gpu_memory() {
+                return true;
+            }
+        }
+
+        false
+    }
+
+    /// Returns true if one of the allocation backends supports dma_buf.
+    pub fn supports_dmabuf(&self) -> bool {
+        for gralloc in self.grallocs.values() {
+            if gralloc.supports_dmabuf() {
+                return true;
+            }
+        }
+
+        false
+    }
+
+    /// Returns the best allocation backend to service a particular request.
+    fn determine_optimal_backend(&self, _info: ImageAllocationInfo) -> GrallocBackend {
+        // This function could be more sophisticated and consider the allocation info.  For example,
+        // nobody has ever tried Mali allocated memory + a mediatek/rockchip display and as such it
+        // probably doesn't work.  In addition, YUV calculations in minigbm have yet to make it
+        // towards the Vulkan api.  This function allows for a variety of quirks, but for now just
+        // choose the most shiny backend that the user has built.  The rationale is "why would you
+        // build it if you don't want to use it".
+        let mut _backend = GrallocBackend::System;
+        #[cfg(feature = "minigbm")]
+        {
+            _backend = GrallocBackend::Minigbm;
+        }
+
+        #[cfg(feature = "vulkano")]
+        {
+            _backend = GrallocBackend::Vulkano;
+        }
+
+        _backend
+    }
+
+    /// Returns a image memory requirements for the given `info` upon success.
+    pub fn get_image_memory_requirements(
+        &mut self,
+        info: ImageAllocationInfo,
+    ) -> RutabagaResult<ImageMemoryRequirements> {
+        let backend = self.determine_optimal_backend(info);
+
+        let gralloc = self
+            .grallocs
+            .get_mut(&backend)
+            .ok_or(RutabagaError::Unsupported)?;
+
+        let mut reqs = gralloc.get_image_memory_requirements(info)?;
+        reqs.size = round_up_to_page_size(reqs.size as usize) as u64;
+        Ok(reqs)
+    }
+
+    /// Allocates memory given the particular `reqs` upon success.
+    pub fn allocate_memory(
+        &mut self,
+        reqs: ImageMemoryRequirements,
+    ) -> RutabagaResult<RutabagaHandle> {
+        let backend = self.determine_optimal_backend(reqs.info);
+
+        let gralloc = self
+            .grallocs
+            .get_mut(&backend)
+            .ok_or(RutabagaError::Unsupported)?;
+
+        gralloc.allocate_memory(reqs)
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn create_render_target() {
+        let gralloc_result = RutabagaGralloc::new();
+        if gralloc_result.is_err() {
+            return;
+        }
+
+        let mut gralloc = gralloc_result.unwrap();
+
+        let info = ImageAllocationInfo {
+            width: 512,
+            height: 1024,
+            drm_format: DrmFormat::new(b'X', b'R', b'2', b'4'),
+            flags: RutabagaGrallocFlags::empty().use_scanout(true),
+        };
+
+        let reqs = gralloc.get_image_memory_requirements(info).unwrap();
+        let min_reqs = canonical_image_requirements(info).unwrap();
+
+        assert_eq!(reqs.strides[0] >= min_reqs.strides[0], true);
+        assert_eq!(reqs.size >= min_reqs.size, true);
+
+        let _handle = gralloc.allocate_memory(reqs).unwrap();
+
+        // Reallocate with same requirements
+        let _handle2 = gralloc.allocate_memory(reqs).unwrap();
+    }
+
+    #[test]
+    fn create_video_buffer() {
+        let gralloc_result = RutabagaGralloc::new();
+        if gralloc_result.is_err() {
+            return;
+        }
+
+        let mut gralloc = gralloc_result.unwrap();
+
+        let info = ImageAllocationInfo {
+            width: 512,
+            height: 1024,
+            drm_format: DrmFormat::new(b'N', b'V', b'1', b'2'),
+            flags: RutabagaGrallocFlags::empty().use_linear(true),
+        };
+
+        let reqs = gralloc.get_image_memory_requirements(info).unwrap();
+        let min_reqs = canonical_image_requirements(info).unwrap();
+
+        assert_eq!(reqs.strides[0] >= min_reqs.strides[0], true);
+        assert_eq!(reqs.strides[1] >= min_reqs.strides[1], true);
+        assert_eq!(reqs.strides[2], 0);
+        assert_eq!(reqs.strides[3], 0);
+
+        assert_eq!(reqs.offsets[0] >= min_reqs.offsets[0], true);
+        assert_eq!(reqs.offsets[1] >= min_reqs.offsets[1], true);
+        assert_eq!(reqs.offsets[2], 0);
+        assert_eq!(reqs.offsets[3], 0);
+
+        assert_eq!(reqs.size >= min_reqs.size, true);
+
+        let _handle = gralloc.allocate_memory(reqs).unwrap();
+
+        // Reallocate with same requirements
+        let _handle2 = gralloc.allocate_memory(reqs).unwrap();
+    }
+}
diff --git a/rutabaga_gfx/src/rutabaga_gralloc/minigbm.rs b/rutabaga_gfx/src/rutabaga_gralloc/minigbm.rs
new file mode 100644
index 0000000..b071781
--- /dev/null
+++ b/rutabaga_gfx/src/rutabaga_gralloc/minigbm.rs
@@ -0,0 +1,242 @@
+// 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.
+
+//! minigbm: implements swapchain allocation using ChromeOS's minigbm library.
+//!
+//! External code found at https://chromium.googlesource.com/chromiumos/platform/minigbm.
+
+#![cfg(feature = "minigbm")]
+
+use std::ffi::CStr;
+use std::fs::File;
+use std::io::{Seek, SeekFrom};
+use std::os::raw::c_char;
+use std::rc::Rc;
+
+use base::{AsRawDescriptor, Error as SysError, FromRawDescriptor};
+
+use crate::rutabaga_gralloc::formats::DrmFormat;
+use crate::rutabaga_gralloc::gralloc::{Gralloc, ImageAllocationInfo, ImageMemoryRequirements};
+use crate::rutabaga_gralloc::minigbm_bindings::*;
+use crate::rutabaga_gralloc::rendernode;
+use crate::rutabaga_utils::*;
+
+struct MinigbmDeviceInner {
+    _fd: File,
+    gbm: *mut gbm_device,
+}
+
+impl Drop for MinigbmDeviceInner {
+    fn drop(&mut self) {
+        // Safe because MinigbmDeviceInner is only constructed with a valid minigbm_device.
+        unsafe {
+            gbm_device_destroy(self.gbm);
+        }
+    }
+}
+
+/// A device capable of allocating `MinigbmBuffer`.
+#[derive(Clone)]
+pub struct MinigbmDevice {
+    minigbm_device: Rc<MinigbmDeviceInner>,
+    last_buffer: Option<Rc<MinigbmBuffer>>,
+    device_name: &'static str,
+}
+
+impl MinigbmDevice {
+    /// Returns a new `MinigbmDevice` if there is a rendernode in `/dev/dri/` that is accepted by
+    /// the minigbm library.
+    pub fn init() -> RutabagaResult<Box<dyn Gralloc>> {
+        let undesired: &[&str] = &["vgem", "pvr"];
+        let fd = rendernode::open_device(undesired)?;
+
+        // gbm_create_device is safe to call with a valid fd, and we check that a valid one is
+        // returned.  If the fd does not refer to a DRM device, gbm_create_device will reject it.
+        let gbm = unsafe { gbm_create_device(fd.as_raw_descriptor()) };
+        if gbm.is_null() {
+            return Err(RutabagaError::SysError(SysError::last()));
+        }
+
+        // Safe because a valid minigbm device has a statically allocated string associated with
+        // it, which is valid for the lifetime of the process.
+        let backend_name: *const c_char = unsafe { gbm_device_get_backend_name(gbm) };
+        let c_str: &CStr = unsafe { CStr::from_ptr(backend_name) };
+        let device_name: &str = c_str.to_str()?;
+
+        Ok(Box::new(MinigbmDevice {
+            minigbm_device: Rc::new(MinigbmDeviceInner { _fd: fd, gbm }),
+            last_buffer: None,
+            device_name,
+        }))
+    }
+}
+
+impl Gralloc for MinigbmDevice {
+    fn supports_external_gpu_memory(&self) -> bool {
+        true
+    }
+
+    fn supports_dmabuf(&self) -> bool {
+        true
+    }
+
+    fn get_image_memory_requirements(
+        &mut self,
+        info: ImageAllocationInfo,
+    ) -> RutabagaResult<ImageMemoryRequirements> {
+        let bo = unsafe {
+            gbm_bo_create(
+                self.minigbm_device.gbm,
+                info.width,
+                info.height,
+                info.drm_format.0,
+                info.flags.0,
+            )
+        };
+        if bo.is_null() {
+            return Err(RutabagaError::SysError(SysError::last()));
+        }
+
+        let mut reqs: ImageMemoryRequirements = Default::default();
+        let gbm_buffer = MinigbmBuffer(bo, self.clone());
+
+        // Intel GPUs typically only use cached memory buffers.  This will change with dGPUs, but
+        // perhaps minigbm will be deprecated by then.  Other display drivers (rockchip, mediatek,
+        // amdgpu) typically use write combine memory.  We can also consider use flags too if this
+        // heuristic proves insufficient.
+        if self.device_name == "i915" {
+            reqs.map_info = RUTABAGA_MAP_CACHE_CACHED;
+        } else {
+            reqs.map_info = RUTABAGA_MAP_CACHE_WC;
+        }
+
+        reqs.modifier = gbm_buffer.format_modifier();
+        for plane in 0..gbm_buffer.num_planes() {
+            reqs.strides[plane] = gbm_buffer.plane_stride(plane);
+            reqs.offsets[plane] = gbm_buffer.plane_offset(plane);
+        }
+
+        let mut fd = gbm_buffer.export()?;
+        let size = fd
+            .seek(SeekFrom::End(0))
+            .map_err(|_| RutabagaError::Unsupported)?;
+
+        // minigbm does have the ability to query image requirements without allocating memory
+        // via the TEST_ALLOC flag.  However, support has only been added in i915.  Until this
+        // flag is supported everywhere, do the actual allocation here and stash it away.
+        if self.last_buffer.is_some() {
+            return Err(RutabagaError::AlreadyInUse);
+        }
+
+        self.last_buffer = Some(Rc::new(gbm_buffer));
+        reqs.info = info;
+        reqs.size = size;
+        Ok(reqs)
+    }
+
+    fn allocate_memory(&mut self, reqs: ImageMemoryRequirements) -> RutabagaResult<RutabagaHandle> {
+        let last_buffer = self.last_buffer.take();
+        if let Some(gbm_buffer) = last_buffer {
+            if gbm_buffer.width() != reqs.info.width
+                || gbm_buffer.height() != reqs.info.height
+                || gbm_buffer.format() != reqs.info.drm_format
+            {
+                return Err(RutabagaError::SpecViolation);
+            }
+
+            let dmabuf = gbm_buffer.export()?;
+            return Ok(RutabagaHandle {
+                os_handle: dmabuf,
+                handle_type: RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
+            });
+        }
+
+        let bo = unsafe {
+            gbm_bo_create(
+                self.minigbm_device.gbm,
+                reqs.info.width,
+                reqs.info.height,
+                reqs.info.drm_format.0,
+                reqs.info.flags.0,
+            )
+        };
+
+        if bo.is_null() {
+            return Err(RutabagaError::SysError(SysError::last()));
+        }
+
+        let gbm_buffer = MinigbmBuffer(bo, self.clone());
+        let dmabuf = gbm_buffer.export()?;
+        Ok(RutabagaHandle {
+            os_handle: dmabuf,
+            handle_type: RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
+        })
+    }
+}
+
+/// An allocation from a `MinigbmDevice`.
+pub struct MinigbmBuffer(*mut gbm_bo, MinigbmDevice);
+
+impl MinigbmBuffer {
+    /// 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) }
+    }
+
+    /// `DrmFormat` of the buffer.
+    pub fn format(&self) -> DrmFormat {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { DrmFormat(gbm_bo_get_format(self.0)) }
+    }
+
+    /// DrmFormat 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_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_plane_count(self.0) as usize }
+    }
+
+    /// Offset in bytes for the given plane.
+    pub fn plane_offset(&self, plane: usize) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_offset(self.0, plane) }
+    }
+
+    /// Length in bytes of one row for the given plane.
+    pub fn plane_stride(&self, plane: usize) -> u32 {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_get_stride_for_plane(self.0, plane) }
+    }
+
+    /// Exports a new dmabuf/prime file descriptor.
+    pub fn export(&self) -> RutabagaResult<File> {
+        // This is always safe to call with a valid gbm_bo pointer.
+        match unsafe { gbm_bo_get_fd(self.0) } {
+            fd if fd >= 0 => {
+                let dmabuf = unsafe { File::from_raw_descriptor(fd) };
+                Ok(dmabuf)
+            }
+            ret => Err(RutabagaError::ComponentError(ret)),
+        }
+    }
+}
+
+impl Drop for MinigbmBuffer {
+    fn drop(&mut self) {
+        // This is always safe to call with a valid gbm_bo pointer.
+        unsafe { gbm_bo_destroy(self.0) }
+    }
+}
diff --git a/gpu_buffer/src/raw.rs b/rutabaga_gfx/src/rutabaga_gralloc/minigbm_bindings.rs
similarity index 98%
rename from gpu_buffer/src/raw.rs
rename to rutabaga_gfx/src/rutabaga_gralloc/minigbm_bindings.rs
index ba07259..9a44fda 100644
--- a/gpu_buffer/src/raw.rs
+++ b/rutabaga_gfx/src/rutabaga_gralloc/minigbm_bindings.rs
@@ -5,6 +5,7 @@
 // Generated with bindgen --whitelist-function='gbm_.*' --whitelist-type='gbm_.*' minigbm/gbm.h
 // Then modified manually
 
+#![cfg(feature = "minigbm")]
 /* Added below line manually */
 #![allow(dead_code, non_camel_case_types)]
 
diff --git a/rutabaga_gfx/src/rutabaga_gralloc/mod.rs b/rutabaga_gfx/src/rutabaga_gralloc/mod.rs
new file mode 100644
index 0000000..4de7cce
--- /dev/null
+++ b/rutabaga_gfx/src/rutabaga_gralloc/mod.rs
@@ -0,0 +1,22 @@
+// Copyright 2021 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.
+
+//! This module implements cross-platform allocation of window system buffers.
+//! In addition, it may perform mappings of GPU buffers.  This is based on
+//! "gralloc", a well-known Android hardware abstaction layer (HAL).
+//!
+//! https://source.android.com/devices/graphics/arch-bq-gralloc
+
+mod formats;
+mod gralloc;
+mod minigbm;
+mod minigbm_bindings;
+mod rendernode;
+mod system_gralloc;
+mod vulkano_gralloc;
+
+pub use formats::DrmFormat;
+pub use gralloc::{
+    ImageAllocationInfo, ImageMemoryRequirements, RutabagaGralloc, RutabagaGrallocFlags,
+};
diff --git a/gpu_buffer/src/rendernode.rs b/rutabaga_gfx/src/rutabaga_gralloc/rendernode.rs
similarity index 89%
rename from gpu_buffer/src/rendernode.rs
rename to rutabaga_gfx/src/rutabaga_gralloc/rendernode.rs
index bbaf50b..bfef367 100644
--- a/gpu_buffer/src/rendernode.rs
+++ b/rutabaga_gfx/src/rutabaga_gralloc/rendernode.rs
@@ -2,8 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#![cfg(feature = "minigbm")]
+
 use std::ffi::CString;
 use std::fs::{File, OpenOptions};
+
 #[cfg(target_pointer_width = "64")]
 use std::os::raw::c_ulong;
 use std::os::raw::{c_char, c_int, c_uint};
@@ -12,6 +15,8 @@
 
 use base::{ioctl_iowr_nr, ioctl_with_mut_ref};
 
+use crate::rutabaga_utils::{RutabagaError, RutabagaResult};
+
 // Consistent with __kernel_size_t in include/uapi/asm-generic/posix_types.h.
 #[cfg(not(target_pointer_width = "64"))]
 #[allow(non_camel_case_types)]
@@ -83,7 +88,7 @@
 
 /// Returns a `fd` for an opened rendernode device, while filtering out specified
 /// undesired drivers.
-pub fn open_device(undesired: &[&str]) -> Result<File, ()> {
+pub fn open_device(undesired: &[&str]) -> RutabagaResult<File> {
     const DRM_DIR_NAME: &str = "/dev/dri";
     const DRM_MAX_MINOR: u32 = 15;
     const RENDER_NODE_START: u32 = 128;
@@ -100,17 +105,5 @@
         }
     }
 
-    Err(())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    #[ignore] // no access to /dev/dri
-    fn open_rendernode_device() {
-        let undesired: &[&str] = &["bad_driver", "another_bad_driver"];
-        open_device(undesired).expect("failed to open rendernode");
-    }
+    Err(RutabagaError::Unsupported)
 }
diff --git a/rutabaga_gfx/src/rutabaga_gralloc/system_gralloc.rs b/rutabaga_gfx/src/rutabaga_gralloc/system_gralloc.rs
new file mode 100644
index 0000000..0baea51
--- /dev/null
+++ b/rutabaga_gfx/src/rutabaga_gralloc/system_gralloc.rs
@@ -0,0 +1,53 @@
+// Copyright 2021 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.
+
+//! Utility file for allocating exportable system memory.  On Linux systems,
+//! this is is often done with memfd.
+
+use base::SharedMemory;
+
+use crate::rutabaga_gralloc::formats::canonical_image_requirements;
+use crate::rutabaga_gralloc::gralloc::{Gralloc, ImageAllocationInfo, ImageMemoryRequirements};
+use crate::rutabaga_utils::*;
+
+/// A gralloc implementation capable of allocation from system memory.
+pub struct SystemGralloc(());
+
+impl SystemGralloc {
+    fn new() -> Self {
+        SystemGralloc(())
+    }
+
+    /// Returns a new `SystemGralloc` instance.
+    pub fn init() -> RutabagaResult<Box<dyn Gralloc>> {
+        Ok(Box::new(SystemGralloc::new()))
+    }
+}
+
+impl Gralloc for SystemGralloc {
+    fn supports_external_gpu_memory(&self) -> bool {
+        false
+    }
+
+    fn supports_dmabuf(&self) -> bool {
+        false
+    }
+
+    fn get_image_memory_requirements(
+        &mut self,
+        info: ImageAllocationInfo,
+    ) -> RutabagaResult<ImageMemoryRequirements> {
+        let mut reqs = canonical_image_requirements(info)?;
+        reqs.map_info = RUTABAGA_MAP_CACHE_CACHED;
+        Ok(reqs)
+    }
+
+    fn allocate_memory(&mut self, reqs: ImageMemoryRequirements) -> RutabagaResult<RutabagaHandle> {
+        let shm = SharedMemory::named("rutabaga_gralloc", reqs.size)?;
+        Ok(RutabagaHandle {
+            os_handle: shm.into(),
+            handle_type: RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD,
+        })
+    }
+}
diff --git a/rutabaga_gfx/src/rutabaga_gralloc/vulkano_gralloc.rs b/rutabaga_gfx/src/rutabaga_gralloc/vulkano_gralloc.rs
new file mode 100644
index 0000000..b74908a
--- /dev/null
+++ b/rutabaga_gfx/src/rutabaga_gralloc/vulkano_gralloc.rs
@@ -0,0 +1,305 @@
+// Copyright 2021 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.
+
+//! vulkano_gralloc: Implements swapchain allocation and memory mapping
+//! using Vulkano.
+//!
+//! External code found at https://github.com/vulkano-rs/vulkano.
+
+#![cfg(feature = "vulkano")]
+
+use std::iter::Empty;
+use std::sync::Arc;
+
+use crate::rutabaga_gralloc::gralloc::{Gralloc, ImageAllocationInfo, ImageMemoryRequirements};
+use crate::rutabaga_utils::*;
+
+use vulkano::device::{Device, DeviceCreationError, DeviceExtensions};
+use vulkano::image::{sys, ImageCreationError, ImageDimensions, ImageUsage};
+
+use vulkano::instance::{
+    Instance, InstanceCreationError, InstanceExtensions, MemoryType, PhysicalDevice,
+};
+
+use vulkano::memory::{
+    DedicatedAlloc, DeviceMemoryAllocError, DeviceMemoryBuilder, ExternalMemoryHandleType,
+    MemoryRequirements,
+};
+
+use vulkano::memory::pool::AllocFromRequirementsFilter;
+use vulkano::sync::Sharing;
+
+/// A gralloc implementation capable of allocation `VkDeviceMemory`.
+pub struct VulkanoGralloc {
+    device: Arc<Device>,
+}
+
+impl VulkanoGralloc {
+    /// Returns a new `VulkanGralloc' instance upon success.
+    pub fn init() -> RutabagaResult<Box<dyn Gralloc>> {
+        // Initialization copied from triangle.rs in Vulkano.  Look there for a more detailed
+        // explanation of VK initialization.
+        let instance = Instance::new(None, &InstanceExtensions::none(), None)?;
+
+        // We should really check for integrated GPU versus dGPU.
+        let physical = PhysicalDevice::enumerate(&instance)
+            .next()
+            .ok_or(RutabagaError::Unsupported)?;
+
+        let queue_family = physical
+            .queue_families()
+            .find(|&q| {
+                // We take the first queue family that supports graphics.
+                q.supports_graphics()
+            })
+            .ok_or(RutabagaError::Unsupported)?;
+
+        let supported_extensions = DeviceExtensions::supported_by_device(physical);
+        let desired_extensions = DeviceExtensions {
+            khr_dedicated_allocation: true,
+            khr_get_memory_requirements2: true,
+            khr_external_memory: true,
+            khr_external_memory_fd: true,
+            ext_external_memory_dmabuf: true,
+            ..DeviceExtensions::none()
+        };
+
+        let intersection = supported_extensions.intersection(&desired_extensions);
+
+        let (device, mut _queues) = Device::new(
+            physical,
+            physical.supported_features(),
+            &intersection,
+            [(queue_family, 0.5)].iter().cloned(),
+        )?;
+
+        Ok(Box::new(VulkanoGralloc { device }))
+    }
+
+    // This function is used safely in this module because gralloc does not:
+    //
+    //  (1) bind images to any memory.
+    //  (2) transition the layout of images.
+    //  (3) transfer ownership of images between queues.
+    //
+    // In addition, we trust Vulkano to validate image parameters are within the Vulkan spec.
+    unsafe fn create_image(
+        &mut self,
+        info: ImageAllocationInfo,
+    ) -> RutabagaResult<(sys::UnsafeImage, MemoryRequirements)> {
+        let usage = match info.flags.uses_rendering() {
+            true => ImageUsage {
+                color_attachment: true,
+                ..ImageUsage::none()
+            },
+            false => ImageUsage {
+                sampled: true,
+                ..ImageUsage::none()
+            },
+        };
+
+        // Reasonable bounds on image width.
+        if info.width == 0 || info.width > 4096 {
+            return Err(RutabagaError::SpecViolation);
+        }
+
+        // Reasonable bounds on image height.
+        if info.height == 0 || info.height > 4096 {
+            return Err(RutabagaError::SpecViolation);
+        }
+
+        let vulkan_format = info.drm_format.vulkan_format()?;
+        let (unsafe_image, memory_requirements) = sys::UnsafeImage::new(
+            self.device.clone(),
+            usage,
+            vulkan_format,
+            ImageDimensions::Dim2d {
+                width: info.width,
+                height: info.height,
+                array_layers: 1,
+                cubemap_compatible: false,
+            },
+            1, /* number of samples */
+            1, /* mipmap count */
+            Sharing::Exclusive::<Empty<_>>,
+            true,  /* linear images only currently */
+            false, /* not preinitialized */
+        )?;
+
+        Ok((unsafe_image, memory_requirements))
+    }
+}
+
+impl Gralloc for VulkanoGralloc {
+    fn supports_external_gpu_memory(&self) -> bool {
+        self.device.loaded_extensions().khr_external_memory
+    }
+
+    fn supports_dmabuf(&self) -> bool {
+        self.device.loaded_extensions().ext_external_memory_dmabuf
+    }
+
+    fn get_image_memory_requirements(
+        &mut self,
+        info: ImageAllocationInfo,
+    ) -> RutabagaResult<ImageMemoryRequirements> {
+        let mut reqs: ImageMemoryRequirements = Default::default();
+
+        let (unsafe_image, memory_requirements) = unsafe { self.create_image(info)? };
+
+        let planar_layout = info.drm_format.planar_layout()?;
+
+        // Safe because we created the image with the linear bit set and verified the format is
+        // not a depth or stencil format.  We are also using the correct image aspect.  Vulkano
+        // will panic if we are not.
+        for plane in 0..planar_layout.num_planes {
+            let aspect = info.drm_format.vulkan_image_aspect(plane)?;
+            let layout = unsafe { unsafe_image.multiplane_color_layout(aspect) };
+            reqs.strides[plane] = layout.row_pitch as u32;
+            reqs.offsets[plane] = layout.offset as u32;
+        }
+
+        let need_visible = info.flags.host_visible();
+        let want_cached = info.flags.host_cached();
+
+        let memory_type = {
+            let filter = |current_type: MemoryType| {
+                if need_visible && !current_type.is_host_visible() {
+                    return AllocFromRequirementsFilter::Forbidden;
+                }
+
+                if !need_visible && current_type.is_device_local() {
+                    return AllocFromRequirementsFilter::Preferred;
+                }
+
+                if need_visible && want_cached && current_type.is_host_cached() {
+                    return AllocFromRequirementsFilter::Preferred;
+                }
+
+                if need_visible
+                    && !want_cached
+                    && current_type.is_host_coherent()
+                    && !current_type.is_host_cached()
+                {
+                    return AllocFromRequirementsFilter::Preferred;
+                }
+
+                AllocFromRequirementsFilter::Allowed
+            };
+
+            let first_loop = self
+                .device
+                .physical_device()
+                .memory_types()
+                .map(|t| (t, AllocFromRequirementsFilter::Preferred));
+            let second_loop = self
+                .device
+                .physical_device()
+                .memory_types()
+                .map(|t| (t, AllocFromRequirementsFilter::Allowed));
+            first_loop
+                .chain(second_loop)
+                .filter(|&(t, _)| (memory_requirements.memory_type_bits & (1 << t.id())) != 0)
+                .find(|&(t, rq)| filter(t) == rq)
+                .ok_or(RutabagaError::Unsupported)?
+                .0
+        };
+
+        reqs.info = info;
+        reqs.size = memory_requirements.size as u64;
+
+        if memory_type.is_host_visible() {
+            if memory_type.is_host_cached() {
+                reqs.map_info = RUTABAGA_MAP_CACHE_CACHED;
+            } else if memory_type.is_host_coherent() {
+                reqs.map_info = RUTABAGA_MAP_CACHE_WC;
+            }
+        }
+
+        reqs.vulkan_info = Some(VulkanInfo {
+            memory_idx: memory_type.id() as u32,
+            physical_device_idx: self.device.physical_device().index() as u32,
+        });
+
+        Ok(reqs)
+    }
+
+    fn allocate_memory(&mut self, reqs: ImageMemoryRequirements) -> RutabagaResult<RutabagaHandle> {
+        let (unsafe_image, memory_requirements) = unsafe { self.create_image(reqs.info)? };
+        let vulkan_info = reqs.vulkan_info.ok_or(RutabagaError::SpecViolation)?;
+        let memory_type = self
+            .device
+            .physical_device()
+            .memory_type_by_id(vulkan_info.memory_idx)
+            .ok_or(RutabagaError::SpecViolation)?;
+
+        let (handle_type, rutabaga_type) =
+            match self.device.loaded_extensions().ext_external_memory_dmabuf {
+                true => (
+                    ExternalMemoryHandleType {
+                        dma_buf: true,
+                        ..ExternalMemoryHandleType::none()
+                    },
+                    RUTABAGA_MEM_HANDLE_TYPE_DMABUF,
+                ),
+                false => (
+                    ExternalMemoryHandleType {
+                        opaque_fd: true,
+                        ..ExternalMemoryHandleType::none()
+                    },
+                    RUTABAGA_MEM_HANDLE_TYPE_OPAQUE_FD,
+                ),
+            };
+
+        let dedicated = match self.device.loaded_extensions().khr_dedicated_allocation {
+            true => {
+                if memory_requirements.prefer_dedicated {
+                    DedicatedAlloc::Image(&unsafe_image)
+                } else {
+                    DedicatedAlloc::None
+                }
+            }
+            false => DedicatedAlloc::None,
+        };
+
+        let device_memory =
+            DeviceMemoryBuilder::new(self.device.clone(), memory_type, reqs.size as usize)
+                .dedicated_info(dedicated)
+                .export_info(handle_type)
+                .build()?;
+
+        let file = device_memory.export_fd(handle_type)?;
+
+        Ok(RutabagaHandle {
+            os_handle: file,
+            handle_type: rutabaga_type,
+        })
+    }
+}
+
+// Vulkano should really define an universal type that wraps all these errors, say
+// "VulkanoError(e)".
+impl From<InstanceCreationError> for RutabagaError {
+    fn from(e: InstanceCreationError) -> RutabagaError {
+        RutabagaError::VkInstanceCreationError(e)
+    }
+}
+
+impl From<ImageCreationError> for RutabagaError {
+    fn from(e: ImageCreationError) -> RutabagaError {
+        RutabagaError::VkImageCreationError(e)
+    }
+}
+
+impl From<DeviceCreationError> for RutabagaError {
+    fn from(e: DeviceCreationError) -> RutabagaError {
+        RutabagaError::VkDeviceCreationError(e)
+    }
+}
+
+impl From<DeviceMemoryAllocError> for RutabagaError {
+    fn from(e: DeviceMemoryAllocError) -> RutabagaError {
+        RutabagaError::VkDeviceMemoryAllocError(e)
+    }
+}
diff --git a/rutabaga_gfx/src/rutabaga_utils.rs b/rutabaga_gfx/src/rutabaga_utils.rs
index ce4a164..9983091 100644
--- a/rutabaga_gfx/src/rutabaga_utils.rs
+++ b/rutabaga_gfx/src/rutabaga_utils.rs
@@ -8,10 +8,20 @@
 use std::fs::File;
 use std::os::raw::c_void;
 use std::path::PathBuf;
+use std::str::Utf8Error;
 
-use base::ExternalMappingError;
+use base::{Error as SysError, ExternalMappingError};
 use data_model::VolatileMemoryError;
 
+#[cfg(feature = "vulkano")]
+use vulkano::device::DeviceCreationError;
+#[cfg(feature = "vulkano")]
+use vulkano::image::ImageCreationError;
+#[cfg(feature = "vulkano")]
+use vulkano::instance::InstanceCreationError;
+#[cfg(feature = "vulkano")]
+use vulkano::memory::DeviceMemoryAllocError;
+
 /// Represents a buffer.  `base` contains the address of a buffer, while `len` contains the length
 /// of the buffer.
 pub struct RutabagaIovec {
@@ -55,7 +65,7 @@
 }
 
 /// Metadata associated with a swapchain, video or camera image.
-#[derive(Debug)]
+#[derive(Default, Copy, Clone, Debug)]
 pub struct Resource3DMetadata {
     pub width: u32,
     pub height: u32,
@@ -65,6 +75,13 @@
     pub modifier: u64,
 }
 
+/// Memory index and physical device index of the associated VkDeviceMemory.
+#[derive(Copy, Clone, Default)]
+pub struct VulkanInfo {
+    pub memory_idx: u32,
+    pub physical_device_idx: u32,
+}
+
 /// Rutabaga context init capset id mask (not upstreamed).
 pub const RUTABAGA_CONTEXT_INIT_CAPSET_ID_MASK: u32 = 0x00ff;
 
@@ -98,7 +115,7 @@
 pub enum RutabagaError {
     /// Indicates `Rutabaga` was already initialized since only one Rutabaga instance per process
     /// is allowed.
-    AlreadyInitialized,
+    AlreadyInUse,
     /// Checked Arithmetic error
     CheckedArithmetic {
         field1: (&'static str, usize),
@@ -114,6 +131,8 @@
     ExportedRutabagaHandle,
     /// A command size was submitted that was invalid.
     InvalidCommandSize(usize),
+    /// Invalid RutabagaComponent
+    InvalidComponent,
     /// Invalid Context ID
     InvalidContextId,
     /// The indicated region of guest memory is invalid.
@@ -127,16 +146,34 @@
     /// Memory copy failure.
     MemCopy(VolatileMemoryError),
     /// An internal Rutabaga component error was returned.
-    RutabagaComponentError(i32),
+    ComponentError(i32),
+    /// Violation of the Rutabaga spec occured.
+    SpecViolation,
+    /// System error returned as a result of rutabaga library operation.
+    SysError(SysError),
     /// The command is unsupported.
     Unsupported,
+    /// Utf8 error.
+    Utf8Error(Utf8Error),
+    /// Image creation error
+    #[cfg(feature = "vulkano")]
+    VkImageCreationError(ImageCreationError),
+    /// Instance creation error
+    #[cfg(feature = "vulkano")]
+    VkInstanceCreationError(InstanceCreationError),
+    /// Device creation error
+    #[cfg(feature = "vulkano")]
+    VkDeviceCreationError(DeviceCreationError),
+    /// Device memory allocation error
+    #[cfg(feature = "vulkano")]
+    VkDeviceMemoryAllocError(DeviceMemoryAllocError),
 }
 
 impl Display for RutabagaError {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         use self::RutabagaError::*;
         match self {
-            AlreadyInitialized => write!(f, "rutabaga component was already initailized"),
+            AlreadyInUse => write!(f, "attempted to use a rutabaga asset already in use"),
             CheckedArithmetic {
                 field1: (label1, value1),
                 field2: (label2, value2),
@@ -156,18 +193,44 @@
             ),
             ExportedRutabagaHandle => write!(f, "failed to export Rutabaga handle"),
             InvalidCommandSize(s) => write!(f, "command buffer submitted with invalid size: {}", s),
+            InvalidComponent => write!(f, "invalid rutabaga component"),
             InvalidContextId => write!(f, "invalid context id"),
             InvalidIovec => write!(f, "an iovec is outside of guest memory's range"),
             InvalidResourceId => write!(f, "invalid resource id"),
             InvalidRutabagaBuild => write!(f, "invalid rutabaga build parameters"),
             MappingFailed(s) => write!(f, "The mapping failed for the following reason: {}", s),
             MemCopy(e) => write!(f, "{}", e),
-            RutabagaComponentError(ret) => write!(f, "rutabaga failed with error {}", ret),
-            Unsupported => write!(f, "gpu renderer function unsupported"),
+            ComponentError(ret) => write!(f, "rutabaga component failed with error {}", ret),
+            SpecViolation => write!(f, "violation of the rutabaga spec"),
+            SysError(e) => write!(f, "rutabaga received a system error: {}", e),
+            Unsupported => write!(f, "feature or function unsupported"),
+            Utf8Error(e) => write!(f, "an utf8 error occured: {}", e),
+            #[cfg(feature = "vulkano")]
+            VkDeviceCreationError(e) => write!(f, "vulkano device creation failure {}", e),
+            #[cfg(feature = "vulkano")]
+            VkDeviceMemoryAllocError(e) => {
+                write!(f, "vulkano device memory allocation failure {}", e)
+            }
+            #[cfg(feature = "vulkano")]
+            VkImageCreationError(e) => write!(f, "vulkano image creation failure {}", e),
+            #[cfg(feature = "vulkano")]
+            VkInstanceCreationError(e) => write!(f, "vulkano instance creation failure {}", e),
         }
     }
 }
 
+impl From<SysError> for RutabagaError {
+    fn from(e: SysError) -> RutabagaError {
+        RutabagaError::SysError(e)
+    }
+}
+
+impl From<Utf8Error> for RutabagaError {
+    fn from(e: Utf8Error) -> RutabagaError {
+        RutabagaError::Utf8Error(e)
+    }
+}
+
 /// The result of an operation in this crate.
 pub type RutabagaResult<T> = std::result::Result<T, RutabagaError>;
 
diff --git a/rutabaga_gfx/src/virgl_renderer.rs b/rutabaga_gfx/src/virgl_renderer.rs
index 93c291b..e37b625 100644
--- a/rutabaga_gfx/src/virgl_renderer.rs
+++ b/rutabaga_gfx/src/virgl_renderer.rs
@@ -182,7 +182,7 @@
         // to whichever thread called this function first.
         static INIT_ONCE: AtomicBool = AtomicBool::new(false);
         if INIT_ONCE.compare_and_swap(false, true, Ordering::Acquire) {
-            return Err(RutabagaError::AlreadyInitialized);
+            return Err(RutabagaError::AlreadyInUse);
         }
 
         // Cookie is intentionally never freed because virglrenderer never gets uninitialized.
@@ -533,6 +533,7 @@
         Err(RutabagaError::Unsupported)
     }
 
+    #[allow(unused_variables)]
     fn create_context(
         &self,
         ctx_id: u32,
diff --git a/src/linux.rs b/src/linux.rs
index 12feeaa..70abc1b 100644
--- a/src/linux.rs
+++ b/src/linux.rs
@@ -49,6 +49,7 @@
 use net_util::{Error as NetError, MacAddress, Tap};
 use remain::sorted;
 use resources::{Alloc, MmioType, SystemAllocator};
+use rutabaga_gfx::RutabagaGralloc;
 use sync::Mutex;
 
 use base::{
@@ -116,6 +117,7 @@
     CreateConsole(arch::serial::Error),
     CreateDiskError(disk::Error),
     CreateEvent(base::Error),
+    CreateGrallocError(rutabaga_gfx::RutabagaError),
     CreateSignalFd(base::SignalFdError),
     CreateSocket(io::Error),
     CreateTapDevice(NetError),
@@ -222,6 +224,7 @@
             CreateConsole(e) => write!(f, "failed to create console device: {}", e),
             CreateDiskError(e) => write!(f, "failed to create virtual disk: {}", e),
             CreateEvent(e) => write!(f, "failed to create event: {}", e),
+            CreateGrallocError(e) => write!(f, "failed to create gralloc: {}", e),
             CreateSignalFd(e) => write!(f, "failed to create signalfd: {}", e),
             CreateSocket(e) => write!(f, "failed to create socket: {}", e),
             CreateTapDevice(e) => write!(f, "failed to create tap device: {}", e),
@@ -2332,6 +2335,7 @@
         (&cfg.battery_type, None)
     };
 
+    let gralloc = RutabagaGralloc::new().map_err(Error::CreateGrallocError)?;
     let map_request: Arc<Mutex<Option<ExternalMapping>>> = Arc::new(Mutex::new(None));
 
     let fs_count = cfg
@@ -2386,6 +2390,7 @@
         cfg.sandbox,
         Arc::clone(&map_request),
         cfg.balloon_bias,
+        gralloc,
     )
 }
 
@@ -2582,6 +2587,7 @@
     sandbox: bool,
     map_request: Arc<Mutex<Option<ExternalMapping>>>,
     balloon_bias: i64,
+    mut gralloc: RutabagaGralloc,
 ) -> Result<()> {
     #[derive(PollToken)]
     enum Token {
@@ -2890,6 +2896,7 @@
                                         &mut linux.vm,
                                         &mut linux.resources,
                                         Arc::clone(&map_request),
+                                        &mut gralloc,
                                     );
                                     if let Err(e) = socket.send(&response) {
                                         error!("failed to send VmMemoryControlResponse: {}", e);
diff --git a/vm_control/Cargo.toml b/vm_control/Cargo.toml
index 2382059..3c59d98 100644
--- a/vm_control/Cargo.toml
+++ b/vm_control/Cargo.toml
@@ -14,6 +14,7 @@
 libc = "*"
 msg_socket = { path = "../msg_socket" }
 resources = { path = "../resources" }
+rutabaga_gfx = { path = "../rutabaga_gfx"}
 sync = { path = "../sync" }
 base = { path = "../base" }
 vm_memory = { path = "../vm_memory" }
diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs
index 7cc59ba..ba86d2f 100644
--- a/vm_control/src/lib.rs
+++ b/vm_control/src/lib.rs
@@ -15,7 +15,6 @@
 
 use std::fmt::{self, Display};
 use std::fs::File;
-use std::io::{Seek, SeekFrom};
 use std::mem::ManuallyDrop;
 use std::os::raw::c_int;
 use std::result::Result as StdResult;
@@ -31,10 +30,24 @@
 };
 use hypervisor::{IrqRoute, IrqSource, Vm};
 use msg_socket::{MsgError, MsgOnSocket, MsgReceiver, MsgResult, MsgSender, MsgSocket};
-use resources::{Alloc, GpuMemoryDesc, MmioType, SystemAllocator};
+use resources::{Alloc, MmioType, SystemAllocator};
+use rutabaga_gfx::{DrmFormat, ImageAllocationInfo, RutabagaGralloc, RutabagaGrallocFlags};
 use sync::Mutex;
 use vm_memory::GuestAddress;
 
+/// 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],
+}
+
 #[cfg(all(target_arch = "x86_64", feature = "gdb"))]
 pub use crate::gdb::*;
 pub use hypervisor::MemSlot;
@@ -341,6 +354,7 @@
         vm: &mut impl Vm,
         sys_allocator: &mut SystemAllocator,
         map_request: Arc<Mutex<Option<ExternalMapping>>>,
+        gralloc: &mut RutabagaGralloc,
     ) -> VmMemoryResponse {
         use self::VmMemoryRequest::*;
         match *self {
@@ -377,25 +391,57 @@
                 height,
                 format,
             } => {
-                let (mut fd, desc) = match sys_allocator.gpu_memory_allocator() {
-                    Some(gpu_allocator) => match gpu_allocator.allocate(width, height, format) {
-                        Ok(v) => v,
-                        Err(e) => return VmMemoryResponse::Err(e),
-                    },
-                    None => return VmMemoryResponse::Err(SysError::new(ENODEV)),
+                let img = ImageAllocationInfo {
+                    width,
+                    height,
+                    drm_format: DrmFormat::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.
+                    flags: RutabagaGrallocFlags::empty().use_linear(true),
                 };
-                // Determine size of buffer using 0 byte seek from end. This is preferred over
-                // `stride * height` as it's not limited to packed pixel formats.
-                let size = match fd.seek(SeekFrom::End(0)) {
-                    Ok(v) => v,
-                    Err(e) => return VmMemoryResponse::Err(SysError::from(e)),
+
+                let reqs = match gralloc.get_image_memory_requirements(img) {
+                    Ok(reqs) => reqs,
+                    Err(e) => {
+                        error!("gralloc failed to get image requirements: {}", e);
+                        return VmMemoryResponse::Err(SysError::new(EINVAL));
+                    }
                 };
-                match register_memory(vm, sys_allocator, &fd, size as usize, None) {
+
+                let handle = match gralloc.allocate_memory(reqs) {
+                    Ok(handle) => handle,
+                    Err(e) => {
+                        error!("gralloc failed to allocate memory: {}", e);
+                        return VmMemoryResponse::Err(SysError::new(EINVAL));
+                    }
+                };
+
+                let mut desc = GpuMemoryDesc::default();
+                for i in 0..3 {
+                    desc.planes[i] = GpuMemoryPlaneDesc {
+                        stride: reqs.strides[i],
+                        offset: reqs.offsets[i],
+                    }
+                }
+
+                match register_memory(
+                    vm,
+                    sys_allocator,
+                    &handle.os_handle,
+                    reqs.size as usize,
+                    None,
+                ) {
                     Ok((pfn, slot)) => VmMemoryResponse::AllocateAndRegisterGpuMemory {
                         // Safe because ownership is transferred to SafeDescriptor via
                         // into_raw_descriptor
                         descriptor: MaybeOwnedDescriptor::Owned(unsafe {
-                            SafeDescriptor::from_raw_descriptor(fd.into_raw_descriptor())
+                            SafeDescriptor::from_raw_descriptor(
+                                handle.os_handle.into_raw_descriptor(),
+                            )
                         }),
                         pfn,
                         slot,
diff --git a/x86_64/src/lib.rs b/x86_64/src/lib.rs
index f1cf6e3..499e9aa 100644
--- a/x86_64/src/lib.rs
+++ b/x86_64/src/lib.rs
@@ -372,7 +372,7 @@
     {
         let has_bios = matches!(components.vm_image, VmImage::Bios(_));
         let mem = Self::setup_memory(components.memory_size, has_bios)?;
-        let mut resources = Self::get_resource_allocator(&mem, components.wayland_dmabuf);
+        let mut resources = Self::get_resource_allocator(&mem);
 
         let vcpu_count = components.vcpu_count;
         let mut vm = create_vm(mem.clone()).map_err(|e| Error::CreateVm(Box::new(e)))?;
@@ -942,13 +942,13 @@
     }
 
     /// Returns a system resource allocator.
-    fn get_resource_allocator(mem: &GuestMemory, gpu_allocation: bool) -> SystemAllocator {
+    fn get_resource_allocator(mem: &GuestMemory) -> SystemAllocator {
         let high_mmio_start = Self::get_high_mmio_base(mem);
         SystemAllocator::builder()
             .add_io_addresses(0xc000, 0x10000)
             .add_low_mmio_addresses(END_ADDR_BEFORE_32BITS, MMIO_SIZE)
             .add_high_mmio_addresses(high_mmio_start, u64::max_value() - high_mmio_start)
-            .create_allocator(X86_64_IRQ_BASE, gpu_allocation)
+            .create_allocator(X86_64_IRQ_BASE)
             .unwrap()
     }
 
diff --git a/x86_64/src/test_integration.rs b/x86_64/src/test_integration.rs
index f779032..7a2e475 100644
--- a/x86_64/src/test_integration.rs
+++ b/x86_64/src/test_integration.rs
@@ -102,7 +102,7 @@
     // guest mem is 400 pages
     let guest_mem = X8664arch::setup_memory(memory_size, false).unwrap();
     // let guest_mem = GuestMemory::new(&[(GuestAddress(0), memory_size)]).unwrap();
-    let mut resources = X8664arch::get_resource_allocator(&guest_mem, false);
+    let mut resources = X8664arch::get_resource_allocator(&guest_mem);
 
     let (hyp, mut vm) = create_vm(guest_mem.clone());
     let (irqchip_socket, device_socket) =