summary refs log tree commit diff
diff options
context:
space:
mode:
authorGurchetan Singh <gurchetansingh@chromium.org>2019-07-25 16:14:54 -0700
committerCommit Bot <commit-bot@chromium.org>2019-08-20 17:46:24 +0000
commitb8a833f6cc5f602823dfab51c9241473536e6235 (patch)
tree7548ca438a1b69068f1549b5ac2e7550f32aba8d
parent84d59e76b37095faf11195e2940978bd2af9e949 (diff)
downloadcrosvm-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.rs195
-rw-r--r--gpu_renderer/src/lib.rs115
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.