gpu: import buffers for rendering from minigbm

BUG=None
TEST=build with --features=gpu; null_platform_test (has tearing)

Change-Id: Ic53ac703971bfdafcff2a4df55ddc4cf382144f1
Reviewed-on: https://chromium-review.googlesource.com/1050989
Commit-Ready: David Riley <davidriley@chromium.org>
Tested-by: David Riley <davidriley@chromium.org>
Reviewed-by: Zach Reizner <zachr@chromium.org>
This commit is contained in:
David Riley 2018-05-22 15:37:22 -07:00 committed by chrome-bot
parent 150daf94c2
commit af9d7edfb7
2 changed files with 191 additions and 25 deletions

View file

@ -18,7 +18,8 @@ use sys_util::{GuestAddress, GuestMemory};
use super::gpu_buffer::{Device, Buffer, Format, Flags};
use super::gpu_display::*;
use super::gpu_renderer::{Box3, Renderer, Context as RendererContext,
Resource as GpuRendererResource, ResourceCreateArgs};
Resource as GpuRendererResource, ResourceCreateArgs,
format_fourcc as renderer_fourcc};
use super::protocol::GpuResponse;
@ -154,6 +155,19 @@ struct BackedBuffer {
display_import: Option<(Rc<RefCell<GpuDisplay>>, u32)>,
backing: Vec<(GuestAddress, usize)>,
buffer: Buffer,
gpu_renderer_resource: Option<GpuRendererResource>,
}
impl BackedBuffer {
fn new_renderer_registered(buffer: Buffer,
gpu_renderer_resource: GpuRendererResource) -> BackedBuffer {
BackedBuffer {
display_import: None,
backing: Vec::new(),
buffer,
gpu_renderer_resource: Some(gpu_renderer_resource),
}
}
}
impl From<Buffer> for BackedBuffer {
@ -162,6 +176,7 @@ impl From<Buffer> for BackedBuffer {
display_import: None,
backing: Vec::new(),
buffer,
gpu_renderer_resource: None,
}
}
}
@ -183,6 +198,10 @@ impl VirglResource for BackedBuffer {
self.backing.clear()
}
fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> {
self.gpu_renderer_resource.as_mut()
}
fn buffer(&self) -> Option<&Buffer> {
Some(&self.buffer)
}
@ -646,6 +665,17 @@ impl Backend {
}
}
pub fn validate_args_as_fourcc(args: ResourceCreateArgs) -> Option<u32> {
if args.depth == 1 &&
args.array_size == 1 &&
args.last_level == 0 &&
args.nr_samples == 0 {
renderer_fourcc(args.format)
} else {
None
}
}
/// Creates a 3D resource with the given properties and associated it with the given id.
pub fn resource_create_3d(&mut self,
id: u32,
@ -663,31 +693,90 @@ impl Backend {
if id == 0 {
return GpuResponse::ErrInvalidResourceId;
}
let create_args = ResourceCreateArgs {
handle: id,
target,
format,
bind,
width,
height,
depth,
array_size,
last_level,
nr_samples,
flags,
};
match self.resources.entry(id) {
Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
Entry::Vacant(slot) => {
let res = self.renderer
.create_resource(ResourceCreateArgs {
handle: id,
target,
format,
bind,
width,
height,
depth,
array_size,
last_level,
nr_samples,
flags,
});
match res {
Ok(res) => {
slot.insert(Box::new(res));
GpuResponse::OkNoData
}
Err(e) => {
error!("failed to create renderer resource: {}", e);
GpuResponse::ErrUnspec
match Backend::validate_args_as_fourcc(create_args) {
Some(fourcc) => {
let buffer = match self.device
.create_buffer(width,
height,
Format::from(fourcc),
Flags::empty().use_scanout(true).use_linear(true)) {
Ok(buffer) => buffer,
Err(e) => {
error!("failed to create buffer for 3d resource {}: {}", format, e);
return GpuResponse::ErrUnspec;
}
};
let dma_buf_fd = match buffer.export_plane_fd(0) {
Ok(dma_buf_fd) => dma_buf_fd,
Err(e) => {
error!("failed to export plane fd: {}", e);
return GpuResponse::ErrUnspec
}
};
let image = match self.renderer
.image_from_dmabuf(fourcc,
width,
height,
dma_buf_fd.as_raw_fd(),
buffer.plane_offset(0),
buffer.plane_stride(0)) {
Ok(image) => image,
Err(e) => {
error!("failed to create egl image: {}", e);
return GpuResponse::ErrUnspec
}
};
let res = self.renderer
.import_resource(create_args, image);
match res {
Ok(res) => {
let mut backed =
BackedBuffer::new_renderer_registered(buffer,
res);
slot.insert(Box::new(backed));
GpuResponse::OkNoData
}
Err(e) => {
error!("failed to import renderer resource: {}",
e);
GpuResponse::ErrUnspec
}
}
},
None => {
let res = self.renderer.create_resource(create_args);
match res {
Ok(res) => {
slot.insert(Box::new(res));
GpuResponse::OkNoData
}
Err(e) => {
error!("failed to create renderer resource: {}",
e);
GpuResponse::ErrUnspec
}
}
}
}
}

View file

@ -19,7 +19,7 @@ use std::marker::PhantomData;
use std::mem::{size_of, transmute, uninitialized};
use std::ops::Deref;
use std::os::raw::{c_void, c_int, c_uint, c_char};
use std::os::unix::io::FromRawFd;
use std::os::unix::io::{FromRawFd, RawFd};
use std::ptr::{null, null_mut};
use std::rc::Rc;
use std::result;
@ -32,7 +32,10 @@ use generated::virglrenderer::*;
pub use generated::virglrenderer::{virgl_renderer_resource_create_args,
virgl_renderer_resource_info};
use generated::epoxy_egl::{EGL_CONTEXT_CLIENT_VERSION, EGL_SURFACE_TYPE, EGL_OPENGL_ES_API,
EGL_NONE, EGL_GL_TEXTURE_2D_KHR, EGLDEBUGPROCKHR, EGLAttrib,
EGL_NONE, EGL_GL_TEXTURE_2D_KHR, EGL_WIDTH, EGL_HEIGHT,
EGL_LINUX_DRM_FOURCC_EXT, EGL_DMA_BUF_PLANE0_FD_EXT,
EGL_DMA_BUF_PLANE0_OFFSET_EXT, EGL_DMA_BUF_PLANE0_PITCH_EXT,
EGL_LINUX_DMA_BUF_EXT, EGLDEBUGPROCKHR, EGLAttrib,
EGLuint64KHR, EGLNativeDisplayType, EGLConfig, EGLContext, EGLDisplay,
EGLSurface, EGLClientBuffer, EGLBoolean, EGLint, EGLenum, EGLImageKHR};
use generated::p_defines::{PIPE_TEXTURE_1D, PIPE_TEXTURE_2D, PIPE_BIND_SAMPLER_VIEW};
@ -301,6 +304,7 @@ impl Deref for EGLFunctions {
pub struct Renderer {
no_sync_send: PhantomData<*mut ()>,
egl_funcs: EGLFunctions,
display: EGLDisplay,
}
impl Renderer {
@ -397,6 +401,7 @@ impl Renderer {
Ok(Renderer {
no_sync_send: PhantomData,
egl_funcs,
display
})
}
@ -458,6 +463,22 @@ impl Renderer {
})
}
/// Imports a resource from an EGLImage.
pub fn import_resource(&self,
mut args: virgl_renderer_resource_create_args,
image: Image)
-> Result<Resource> {
let ret = unsafe { virgl_renderer_resource_import_eglimage(&mut args, image.image) };
ret_to_res(ret)?;
Ok(Resource {
id: args.handle,
backing_iovecs: Vec::new(),
backing_mem: None,
egl_funcs: self.egl_funcs.clone(),
no_sync_send: PhantomData,
})
}
/// Helper that creates a simple 1 dimensional resource with basic metadata.
pub fn create_tex_1d(&self, id: u32, width: u32) -> Result<Resource> {
self.create_resource(virgl_renderer_resource_create_args {
@ -491,6 +512,47 @@ impl Renderer {
flags: 0,
})
}
/// Creates an EGLImage from a DMA buffer.
pub fn image_from_dmabuf(&self,
fourcc: u32,
width: u32,
height: u32,
fd: RawFd,
offset: u32,
stride: u32) -> Result<Image> {
let mut attrs = [EGL_WIDTH as EGLint,
width as EGLint,
EGL_HEIGHT as EGLint,
height as EGLint,
EGL_LINUX_DRM_FOURCC_EXT as EGLint,
fourcc as EGLint,
EGL_DMA_BUF_PLANE0_FD_EXT as EGLint,
fd as EGLint,
EGL_DMA_BUF_PLANE0_OFFSET_EXT as EGLint,
offset as EGLint,
EGL_DMA_BUF_PLANE0_PITCH_EXT as EGLint,
stride as EGLint,
EGL_NONE as EGLint];
let image = unsafe {
(self.egl_funcs.CreateImageKHR)(self.display,
0 as EGLContext,
EGL_LINUX_DMA_BUF_EXT,
null_mut() as EGLClientBuffer,
attrs.as_mut_ptr())
};
if image.is_null() {
return Err(Error::CreateImage);
}
Ok(Image {
egl_funcs: self.egl_funcs.clone(),
egl_dpy: self.display,
image
})
}
}
/// A context in which resources can be attached/detached and commands can be submitted.
@ -548,6 +610,21 @@ impl Drop for Context {
}
}
/// A wrapper of an EGLImage to manage its destruction.
pub struct Image {
egl_funcs: EGLFunctions,
egl_dpy: EGLDisplay,
image: EGLImageKHR,
}
impl Drop for Image {
fn drop(&mut self) {
unsafe {
(self.egl_funcs.DestroyImageKHR)(self.egl_dpy, self.image);
}
}
}
/// A DMABUF file descriptor handle and metadata returned from `Resource::export`.
#[derive(Debug)]
pub struct ExportedResource {