summary refs log tree commit diff
path: root/devices/src/virtio/gpu/backend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'devices/src/virtio/gpu/backend.rs')
-rw-r--r--devices/src/virtio/gpu/backend.rs145
1 files changed, 107 insertions, 38 deletions
diff --git a/devices/src/virtio/gpu/backend.rs b/devices/src/virtio/gpu/backend.rs
index 8f693cc..8dd7806 100644
--- a/devices/src/virtio/gpu/backend.rs
+++ b/devices/src/virtio/gpu/backend.rs
@@ -76,7 +76,15 @@ trait VirglResource {
     );
 
     /// Reads from the given rectangle of pixels in the resource to the `dst` slice of memory.
-    fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice);
+    fn read_to_volatile(
+        &mut self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        dst: VolatileSlice,
+        dst_stride: u32,
+    );
 }
 
 impl VirglResource for GpuRendererResource {
@@ -125,12 +133,20 @@ impl VirglResource for GpuRendererResource {
         }
     }
 
-    fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice) {
+    fn read_to_volatile(
+        &mut self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        dst: VolatileSlice,
+        dst_stride: u32,
+    ) {
         let res = GpuRendererResource::read_to_volatile(
             self,
             None,
             0,
-            0,
+            dst_stride,
             0, /* layer_stride */
             Box3::new_2d(x, y, width, height),
             0, /* offset */
@@ -278,8 +294,19 @@ impl VirglResource for BackedBuffer {
         }
     }
 
-    fn read_to_volatile(&mut self, x: u32, y: u32, width: u32, height: u32, dst: VolatileSlice) {
-        if let Err(e) = self.buffer.read_to_volatile(x, y, width, height, 0, dst) {
+    fn read_to_volatile(
+        &mut self,
+        x: u32,
+        y: u32,
+        width: u32,
+        height: u32,
+        dst: VolatileSlice,
+        dst_stride: u32,
+    ) {
+        if let Err(e) = self
+            .buffer
+            .read_to_volatile(x, y, width, height, 0, dst, dst_stride)
+        {
             error!("failed to copy resource: {}", e);
         }
     }
@@ -292,7 +319,7 @@ impl VirglResource for BackedBuffer {
 /// failure, or requested data for the given command.
 pub struct Backend {
     display: Rc<RefCell<GpuDisplay>>,
-    device: Device,
+    device: Option<Device>,
     renderer: Renderer,
     resources: Map<u32, Box<dyn VirglResource>>,
     contexts: Map<u32, RendererContext>,
@@ -308,8 +335,11 @@ impl Backend {
     /// Creates a new backend for virtio-gpu that realizes all commands using the given `device` for
     /// allocating buffers, `display` for showing the results, and `renderer` for submitting
     /// rendering commands.
+    ///
+    /// If the `device` is None, all buffer allocations will be done internally by the renderer or
+    /// the display and buffer data is copied as needed.
     pub fn new(
-        device: Device,
+        device: Option<Device>,
         display: GpuDisplay,
         renderer: Renderer,
         gpu_device_socket: VmMemoryControlRequestSocket,
@@ -377,30 +407,54 @@ impl Backend {
         id: u32,
         width: u32,
         height: u32,
-        fourcc: u32,
+        format: u32,
     ) -> GpuResponse {
         if id == 0 {
             return GpuResponse::ErrInvalidResourceId;
         }
         match self.resources.entry(id) {
-            Entry::Vacant(slot) => {
-                let res = self.device.create_buffer(
-                    width,
-                    height,
-                    Format::from(fourcc),
-                    Flags::empty().use_scanout(true).use_linear(true),
-                );
-                match res {
-                    Ok(res) => {
-                        slot.insert(Box::from(BackedBuffer::from(res)));
-                        GpuResponse::OkNoData
+            Entry::Vacant(slot) => match self.device.as_ref() {
+                Some(device) => match renderer_fourcc(format) {
+                    Some(fourcc) => {
+                        let res = device.create_buffer(
+                            width,
+                            height,
+                            Format::from(fourcc),
+                            Flags::empty().use_scanout(true).use_linear(true),
+                        );
+                        match res {
+                            Ok(res) => {
+                                slot.insert(Box::from(BackedBuffer::from(res)));
+                                GpuResponse::OkNoData
+                            }
+                            Err(_) => {
+                                error!("failed to create renderer resource {}", fourcc);
+                                GpuResponse::ErrUnspec
+                            }
+                        }
+                    }
+                    None => {
+                        error!(
+                            "unrecognized format can not be converted to fourcc {}",
+                            format
+                        );
+                        GpuResponse::ErrInvalidParameter
                     }
-                    Err(_) => {
-                        error!("failed to create renderer resource {}", fourcc);
-                        GpuResponse::ErrUnspec
+                },
+                None => {
+                    let res = self.renderer.create_resource_2d(id, width, height, format);
+                    match res {
+                        Ok(res) => {
+                            slot.insert(Box::new(res));
+                            GpuResponse::OkNoData
+                        }
+                        Err(e) => {
+                            error!("failed to create renderer resource: {}", e);
+                            GpuResponse::ErrUnspec
+                        }
                     }
                 }
-            }
+            },
             Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
         }
     }
@@ -445,10 +499,10 @@ impl Backend {
         &mut self,
         resource_id: u32,
         surface_id: u32,
-        x: u32,
-        y: u32,
-        width: u32,
-        height: u32,
+        _x: u32,
+        _y: u32,
+        _width: u32,
+        _height: u32,
     ) -> GpuResponse {
         let resource = match self.resources.get_mut(&resource_id) {
             Some(r) => r,
@@ -461,12 +515,13 @@ impl Backend {
         }
 
         // Import failed, fall back to a copy.
-        let display = self.display.borrow_mut();
+        let mut display = self.display.borrow_mut();
         // Prevent overwriting a buffer that is currently being used by the compositor.
         if display.next_buffer_in_use(surface_id) {
             return GpuResponse::OkNoData;
         }
-        let fb = match display.framebuffer_memory(surface_id) {
+
+        let fb = match display.framebuffer_region(surface_id, 0, 0, DEFAULT_WIDTH, DEFAULT_HEIGHT) {
             Some(fb) => fb,
             None => {
                 error!("failed to access framebuffer for surface {}", surface_id);
@@ -474,7 +529,14 @@ impl Backend {
             }
         };
 
-        resource.read_to_volatile(x, y, width, height, fb);
+        resource.read_to_volatile(
+            0,
+            0,
+            DEFAULT_WIDTH,
+            DEFAULT_HEIGHT,
+            fb.as_volatile_slice(),
+            fb.stride(),
+        );
         display.flip(surface_id);
 
         GpuResponse::OkNoData
@@ -599,10 +661,16 @@ impl Backend {
             // Importing failed, so try copying the pixels into the surface's slower shared memory
             // framebuffer.
             if let Some(buffer) = resource.buffer() {
-                if let Some(fb) = self.display.borrow_mut().framebuffer_memory(cursor_surface) {
-                    if let Err(e) =
-                        buffer.read_to_volatile(0, 0, buffer.width(), buffer.height(), 0, fb)
-                    {
+                if let Some(fb) = self.display.borrow_mut().framebuffer(cursor_surface) {
+                    if let Err(e) = buffer.read_to_volatile(
+                        0,
+                        0,
+                        buffer.width(),
+                        buffer.height(),
+                        0,
+                        fb.as_volatile_slice(),
+                        fb.stride(),
+                    ) {
                         error!("failed to copy resource to cursor: {}", e);
                         return GpuResponse::ErrInvalidParameter;
                     }
@@ -619,7 +687,7 @@ impl Backend {
     pub fn move_cursor(&mut self, x: u32, y: u32) -> GpuResponse {
         if let Some(cursor_surface) = self.cursor_surface {
             if let Some(scanout_surface) = self.scanout_surface {
-                let display = self.display.borrow_mut();
+                let mut display = self.display.borrow_mut();
                 display.set_position(cursor_surface, x, y);
                 display.commit(scanout_surface);
             }
@@ -751,10 +819,11 @@ impl Backend {
         match self.resources.entry(id) {
             Entry::Occupied(_) => GpuResponse::ErrInvalidResourceId,
             Entry::Vacant(slot) => {
-                if Backend::allocate_using_minigbm(create_args) {
+                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 self.device.create_buffer(
+                            let buffer = match device.create_buffer(
                                 width,
                                 height,
                                 Format::from(fourcc),
@@ -763,7 +832,7 @@ impl Backend {
                                 Ok(buffer) => buffer,
                                 Err(_) => {
                                     // Attempt to allocate the buffer without scanout flag.
-                                    match self.device.create_buffer(
+                                    match device.create_buffer(
                                         width,
                                         height,
                                         Format::from(fourcc),