mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-28 17:44:10 +00:00
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:
parent
150daf94c2
commit
af9d7edfb7
2 changed files with 191 additions and 25 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue