diff options
author | Gurchetan Singh <gurchetansingh@chromium.org> | 2019-07-25 16:14:54 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-08-20 17:46:24 +0000 |
commit | b8a833f6cc5f602823dfab51c9241473536e6235 (patch) | |
tree | 7548ca438a1b69068f1549b5ac2e7550f32aba8d | |
parent | 84d59e76b37095faf11195e2940978bd2af9e949 (diff) | |
download | crosvm-b8a833f6cc5f602823dfab51c9241473536e6235.tar crosvm-b8a833f6cc5f602823dfab51c9241473536e6235.tar.gz crosvm-b8a833f6cc5f602823dfab51c9241473536e6235.tar.bz2 crosvm-b8a833f6cc5f602823dfab51c9241473536e6235.tar.lz crosvm-b8a833f6cc5f602823dfab51c9241473536e6235.tar.xz crosvm-b8a833f6cc5f602823dfab51c9241473536e6235.tar.zst crosvm-b8a833f6cc5f602823dfab51c9241473536e6235.zip |
gpu_renderer: use GBM inside virglrenderer
With YUV support + modifier support coming up, it makes sense to move GBM allocation inside virglrenderer so we can upstream our use cases. In addition, this allows us to use gbm_bo_map(..) for the freecad issue, which would otherwise be resolved through local patches in our graphics drivers. BUG=chromium:906811 TEST=freecad works without Mesa patches Change-Id: I61db5c58a5bc5a79fda3cec8ad6c322fae6acc9e Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1725450 Tested-by: Gurchetan Singh <gurchetansingh@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Gurchetan Singh <gurchetansingh@chromium.org> Reviewed-by: Gurchetan Singh <gurchetansingh@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org> Auto-Submit: Gurchetan Singh <gurchetansingh@chromium.org>
-rw-r--r-- | devices/src/virtio/gpu/backend.rs | 195 | ||||
-rw-r--r-- | gpu_renderer/src/lib.rs | 115 |
2 files changed, 84 insertions, 226 deletions
diff --git a/devices/src/virtio/gpu/backend.rs b/devices/src/virtio/gpu/backend.rs index 8dd7806..99e3449 100644 --- a/devices/src/virtio/gpu/backend.rs +++ b/devices/src/virtio/gpu/backend.rs @@ -14,14 +14,13 @@ use std::usize; use data_model::*; use msg_socket::{MsgReceiver, MsgSender}; -use sys_util::{error, warn, GuestAddress, GuestMemory}; +use sys_util::{error, GuestAddress, GuestMemory}; use gpu_buffer::{Buffer, Device, Flags, Format}; use gpu_display::*; use gpu_renderer::{ format_fourcc as renderer_fourcc, Box3, Context as RendererContext, Image as RendererImage, - Renderer, Resource as GpuRendererResource, ResourceCreateArgs, VIRGL_RES_BIND_SCANOUT, - VIRGL_RES_BIND_SHARED, + Renderer, Resource as GpuRendererResource, ResourceCreateArgs, }; use super::protocol::{ @@ -54,7 +53,13 @@ trait VirglResource { } /// Returns the renderer's concrete `GpuRendererResource` for this resource, if it has one. - fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> { + fn gpu_renderer_resource_mut(&mut self) -> Option<&mut GpuRendererResource> { + None + } + + /// Returns the renderer's concrete non-mutable `GpuRendererResource` for this resource, if + /// it has one. + fn gpu_renderer_resource(&self) -> Option<&GpuRendererResource> { None } @@ -111,7 +116,11 @@ impl VirglResource for GpuRendererResource { self.detach_backing(); } - fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> { + fn gpu_renderer_resource_mut(&mut self) -> Option<&mut GpuRendererResource> { + Some(self) + } + + fn gpu_renderer_resource(&self) -> Option<&GpuRendererResource> { Some(self) } @@ -167,22 +176,6 @@ struct BackedBuffer { _image: Option<RendererImage>, } -impl BackedBuffer { - fn new_renderer_registered( - buffer: Buffer, - gpu_renderer_resource: GpuRendererResource, - image: RendererImage, - ) -> BackedBuffer { - BackedBuffer { - display_import: None, - backing: Vec::new(), - buffer, - gpu_renderer_resource: Some(gpu_renderer_resource), - _image: Some(image), - } - } -} - impl From<Buffer> for BackedBuffer { fn from(buffer: Buffer) -> BackedBuffer { BackedBuffer { @@ -220,10 +213,14 @@ impl VirglResource for BackedBuffer { self.backing.clear(); } - fn gpu_renderer_resource(&mut self) -> Option<&mut GpuRendererResource> { + fn gpu_renderer_resource_mut(&mut self) -> Option<&mut GpuRendererResource> { self.gpu_renderer_resource.as_mut() } + fn gpu_renderer_resource(&self) -> Option<&GpuRendererResource> { + self.gpu_renderer_resource.as_ref() + } + fn buffer(&self) -> Option<&Buffer> { Some(&self.buffer) } @@ -385,8 +382,9 @@ impl Backend { ResourceRequest::GetResource { id } => self .resources .get(&id) - .and_then(|resource| resource.buffer()) - .and_then(|buffer| buffer.export_plane_fd(0).ok()) + .and_then(|resource| resource.gpu_renderer_resource()) + .and_then(|gpu_renderer_resource| gpu_renderer_resource.export().ok()) + .and_then(|export| Some(export.1)) .map(ResourceResponse::Resource) .unwrap_or(ResourceResponse::Invalid), }; @@ -747,7 +745,7 @@ impl Backend { self.contexts.get_mut(&ctx_id), self.resources .get_mut(&res_id) - .and_then(|res| res.gpu_renderer_resource()), + .and_then(|res| res.gpu_renderer_resource_mut()), ) { (Some(ctx), Some(res)) => { ctx.attach(res); @@ -764,7 +762,7 @@ impl Backend { self.contexts.get_mut(&ctx_id), self.resources .get_mut(&res_id) - .and_then(|res| res.gpu_renderer_resource()), + .and_then(|res| res.gpu_renderer_resource_mut()), ) { (Some(ctx), Some(res)) => { ctx.detach(res); @@ -775,14 +773,6 @@ impl Backend { } } - pub fn allocate_using_minigbm(args: ResourceCreateArgs) -> bool { - args.bind & (VIRGL_RES_BIND_SCANOUT | VIRGL_RES_BIND_SHARED) != 0 - && args.depth == 1 - && args.array_size == 1 - && args.last_level == 0 - && args.nr_samples == 0 - } - /// Creates a 3D resource with the given properties and associated it with the given id. pub fn resource_create_3d( &mut self, @@ -819,120 +809,45 @@ impl Backend { match self.resources.entry(id) { Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId, Entry::Vacant(slot) => { - if self.device.is_some() && Backend::allocate_using_minigbm(create_args) { - let device = self.device.as_ref().unwrap(); - match renderer_fourcc(create_args.format) { - Some(fourcc) => { - let buffer = match device.create_buffer( - width, - height, - Format::from(fourcc), - Flags::empty().use_scanout(true).use_rendering(true), - ) { - Ok(buffer) => buffer, - Err(_) => { - // Attempt to allocate the buffer without scanout flag. - match device.create_buffer( - width, - height, - Format::from(fourcc), - Flags::empty().use_rendering(true), - ) { - Ok(buffer) => buffer, - Err(e) => { - error!( - "failed to create buffer for 3d resource {}: {}", - format, e - ); - return GpuResponse::ErrUnspec; - } - } + let res = self.renderer.create_resource(create_args); + match res { + Ok(res) => { + let query = match res.query() { + Ok(query) => query, + Err(_) => return GpuResponse::ErrUnspec, + }; + + let response = match query.out_num_fds { + 0 => GpuResponse::OkNoData, + 1 => { + let mut plane_info = Vec::with_capacity(4); + for plane_index in 0..4 { + plane_info.push(GpuResponsePlaneInfo { + stride: query.out_strides[plane_index], + offset: query.out_offsets[plane_index], + }); } - }; - 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 format_modifier = buffer.format_modifier(); - let mut plane_info = Vec::with_capacity(buffer.num_planes()); - for plane_index in 0..buffer.num_planes() { - plane_info.push(GpuResponsePlaneInfo { - stride: buffer.plane_stride(plane_index), - offset: buffer.plane_offset(plane_index), - }); - } - let backed = - BackedBuffer::new_renderer_registered(buffer, res, image); - slot.insert(Box::new(backed)); - GpuResponse::OkResourcePlaneInfo { - format_modifier, - plane_info, - } - } - Err(e) => { - error!("failed to import renderer resource: {}", e); - GpuResponse::ErrUnspec - } - } - } - None => { - warn!( - "failed to get fourcc for minigbm 3d resource {}, falling back", - format - ); - 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 + let format_modifier = query.out_modifier; + GpuResponse::OkResourcePlaneInfo { + format_modifier, + plane_info, } } - } + _ => return GpuResponse::ErrUnspec, + }; + + slot.insert(Box::new(res)); + response } - } else { - 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 - } + Err(e) => { + error!("failed to create renderer resource: {}", e); + GpuResponse::ErrUnspec } } } } } - /// Copes the given 3D rectangle of pixels of the given resource's backing memory to the host /// side resource. pub fn transfer_to_resource_3d( @@ -958,7 +873,7 @@ impl Backend { }, }; match self.resources.get_mut(&res_id) { - Some(res) => match res.gpu_renderer_resource() { + Some(res) => match res.gpu_renderer_resource_mut() { Some(res) => { let transfer_box = Box3 { x, @@ -1009,7 +924,7 @@ impl Backend { }, }; match self.resources.get_mut(&res_id) { - Some(res) => match res.gpu_renderer_resource() { + Some(res) => match res.gpu_renderer_resource_mut() { Some(res) => { let transfer_box = Box3 { x, diff --git a/gpu_renderer/src/lib.rs b/gpu_renderer/src/lib.rs index 908a83a..6d05070 100644 --- a/gpu_renderer/src/lib.rs +++ b/gpu_renderer/src/lib.rs @@ -51,6 +51,8 @@ pub use crate::pipe_format_fourcc::pipe_format_fourcc as format_fourcc; pub type ResourceCreateArgs = virgl_renderer_resource_create_args; /// Information returned from `Resource::get_info`. pub type ResourceInfo = virgl_renderer_resource_info; +/// Some of the information returned from `Resource::export_query`. +pub type Query = virgl_renderer_export_query; /// An error generated while using this crate. #[derive(Debug)] @@ -788,25 +790,6 @@ impl Drop for Image { } } -/// A DMABUF file descriptor handle and metadata returned from `Resource::export`. -#[derive(Debug)] -pub struct ExportedResource { - /// The file descriptor that represents the DMABUF kernel object. - pub dmabuf: File, - /// The width in pixels of the exported resource. - pub width: u32, - /// The height in pixels of the exported resource. - pub height: u32, - /// The fourcc identifier for the format of the resource. - pub fourcc: u32, - /// Extra modifiers for the format. - pub modifiers: u64, - /// The number of bytes between successive rows in the exported resource. - pub stride: u32, - /// The number of bytes from the start of the exported resource to the first pixel. - pub offset: u32, -} - /// A resource handle used by the renderer. pub struct Resource { id: u32, @@ -830,80 +813,40 @@ impl Resource { Ok(res_info) } - /// Performs an export of this resource so that it may be imported by other processes. - pub fn export(&self) -> Result<ExportedResource> { - let egl_funcs = match self.egl_funcs.as_ref() { - Some(f) => f, - None => return Err(Error::ExportUnsupported), - }; + /// Retrieves metadata suitable for export about this resource. If "export_fd" is true, + /// performs an export of this resource so that it may be imported by other processes. + fn export_query(&self, export_fd: bool) -> Result<Query> { + let mut query: Query = Default::default(); + query.hdr.stype = VIRGL_RENDERER_STRUCTURE_TYPE_EXPORT_QUERY; + query.hdr.stype_version = 0; + query.hdr.size = size_of::<Query>() as u32; + query.in_resource_id = self.id; + query.in_export_fds = if export_fd { 1 } else { 0 }; - let res_info = self.get_info()?; - let mut fourcc = 0; - let mut modifiers = 0; - let mut fd = -1; - let mut stride = 0; - let mut offset = 0; - // Always safe on the same thread with an already initialized virglrenderer. - unsafe { - virgl_renderer_force_ctx_0(); - } - // These are trivially safe and always return successfully because we bind the context in - // the previous line. - let egl_dpy: EGLDisplay = unsafe { (egl_funcs.GetCurrentDisplay)() }; - let egl_ctx: EGLContext = unsafe { (egl_funcs.GetCurrentContext)() }; + // Safe because the image parameters are stack variables of the correct type. + let ret = + unsafe { virgl_renderer_execute(&mut query as *mut _ as *mut c_void, query.hdr.size) }; - // Safe because a valid display, context, and texture ID are given. The attribute list is - // not needed. The result is checked to ensure the returned image is valid. - let image = unsafe { - (egl_funcs.CreateImageKHR)( - egl_dpy, - egl_ctx, - EGL_GL_TEXTURE_2D_KHR, - res_info.tex_id as EGLClientBuffer, - null(), - ) - }; - - if image.is_null() { - return Err(Error::CreateImage); - } - - // Safe because the display and image are valid and each function call is checked for - // success. The returned image parameters are stored in stack variables of the correct type. - let export_success = unsafe { - (egl_funcs.ExportDMABUFImageQueryMESA)( - egl_dpy, - image, - &mut fourcc, - null_mut(), - &mut modifiers, - ) != 0 - && (egl_funcs.ExportDRMImageMESA)(egl_dpy, image, &mut fd, &mut stride, &mut offset) - != 0 - }; + ret_to_res(ret)?; + Ok(query) + } - // Safe because we checked that the image was valid and nobody else owns it. The image does - // not need to be around for the dmabuf to be valid. - unsafe { - (egl_funcs.DestroyImageKHR)(egl_dpy, image); - } + /// Returns resource metadata. + pub fn query(&self) -> Result<Query> { + self.export_query(false) + } - if !export_success || fd < 0 { + /// Returns resource metadata and exports the associated dma-buf. + pub fn export(&self) -> Result<(Query, File)> { + let query = self.export_query(true)?; + if query.out_num_fds != 1 || query.out_fds[0] < 0 { return Err(Error::ExportedResourceDmabuf); } - // Safe because the FD was just returned by a successful EGL call so it must be valid and - // owned by us. - let dmabuf = unsafe { File::from_raw_fd(fd) }; - Ok(ExportedResource { - dmabuf, - width: res_info.width, - height: res_info.height, - fourcc: fourcc as u32, - modifiers, - stride: stride as u32, - offset: offset as u32, - }) + // Safe because the FD was just returned by a successful virglrenderer call so it must + // be valid and owned by us. + let dmabuf = unsafe { File::from_raw_fd(query.out_fds[0]) }; + Ok((query, dmabuf)) } /// Attaches a scatter-gather mapping of guest memory to this resource which used for transfers. |