diff mbox

qxl-render: call ppm_save on bh

Message ID 1331018231-30899-1-git-send-email-alevy@redhat.com
State New
Headers show

Commit Message

Alon Levy March 6, 2012, 7:17 a.m. UTC
Uses the newly introduced hw_screen_dump_async. Now that the deadlock
with virt-manager is fixed we need to call ppm_save in a bh, with the
new command we can notify virt-manager using the SCREEN_DUMP_COMPLETE
event.

Signed-off-by: Alon Levy <alevy@redhat.com>
---
This needs to go on top of [PATCH v3 0/3] screendump async command
 http://patchwork.ozlabs.org/patch/144706/
 http://patchwork.ozlabs.org/patch/144705/
 http://patchwork.ozlabs.org/patch/144704/
 (the patchwork ids are the reverse of the patch order, wierd).

 hw/qxl-render.c    |   79 +++++++++++++++++++++++++++++++++++++++++++++++++--
 hw/qxl.c           |   36 +++++++++++++++++++----
 hw/qxl.h           |    3 +-
 ui/spice-display.h |    5 +++
 4 files changed, 112 insertions(+), 11 deletions(-)
diff mbox

Patch

diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index 25857f6..340fed7 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -19,6 +19,7 @@ 
  * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
+#include "console.h"
 #include "qxl.h"
 
 static void qxl_blit(PCIQXLDevice *qxl, QXLRect *rect)
@@ -148,19 +149,69 @@  static void qxl_render_update_area_unlocked(PCIQXLDevice *qxl)
 }
 
 /*
+ * struct used just for ppm save bh. We don't actually support multiple qxl
+ * screendump yet, but a) we will, and b) exporting qxl0 from qxl.c looks
+ * uglier imo.
+ */
+typedef struct QXLPPMSaveBHData {
+    PCIQXLDevice *qxl;
+    QXLCookie *cookie;
+} QXLPPMSaveBHData;
+
+static void qxl_cookie_render_free(PCIQXLDevice *qxl, QXLCookie *cookie)
+{
+    g_free(cookie->u.render.filename);
+    if (cookie->u.render.async && cookie->u.render.cb) {
+        (*cookie->u.render.cb)(cookie->u.render.cb_opaque);
+    }
+    g_free(cookie);
+    --qxl->render_update_cookie_num;
+}
+
+static void qxl_render_ppm_save_bh(void *opaque)
+{
+    QXLPPMSaveBHData *data = opaque;
+    PCIQXLDevice *qxl = data->qxl;
+    QXLCookie *cookie = data->cookie;
+    QEMUBH *bh = cookie->u.render.ppm_save_bh;
+
+    qemu_mutex_lock(&qxl->ssd.lock);
+    dprint(qxl, 1, "%s: %p (primary %p)\n", __func__,
+           qxl->ssd.ds->surface->data, qxl->guest_primary.data);
+    qxl_render_update_area_unlocked(qxl);
+    ppm_save(cookie->u.render.filename, qxl->ssd.ds->surface);
+    qxl_cookie_render_free(qxl, cookie);
+    qemu_mutex_unlock(&qxl->ssd.lock);
+    g_free(data);
+    qemu_bh_delete(bh);
+}
+
+/*
  * use ssd.lock to protect render_update_cookie_num.
  * qxl_render_update is called by io thread or vcpu thread, and the completion
  * callbacks are called by spice_server thread, defering to bh called from the
  * io thread.
  */
-void qxl_render_update(PCIQXLDevice *qxl)
+void qxl_render_update(PCIQXLDevice *qxl, const char *filename, bool async,
+                       vga_hw_screen_dump_async_cb_ptr cb, void *cb_opaque)
 {
     QXLCookie *cookie;
+    QEMUBH *ppm_save_bh;
+    QXLPPMSaveBHData *ppm_save_bh_data;
 
+    assert(!async || cb);
     qemu_mutex_lock(&qxl->ssd.lock);
 
     if (!runstate_is_running() || !qxl->guest_primary.commands) {
         qxl_render_update_area_unlocked(qxl);
+        if (filename) {
+            dprint(qxl, 1, "%s: screendump with no pending commands\n",
+                   __func__);
+            ppm_save(filename, qxl->ssd.ds->surface);
+        }
+        if (async) {
+            (*cb)(cb_opaque);
+        }
         qemu_mutex_unlock(&qxl->ssd.lock);
         return;
     }
@@ -171,8 +222,24 @@  void qxl_render_update(PCIQXLDevice *qxl)
     cookie = qxl_cookie_new(QXL_COOKIE_TYPE_RENDER_UPDATE_AREA,
                             0);
     qxl_set_rect_to_surface(qxl, &cookie->u.render.area);
+    if (filename && async) {
+        ppm_save_bh_data = g_malloc0(sizeof(*ppm_save_bh_data));
+        ppm_save_bh_data->qxl = qxl;
+        ppm_save_bh_data->cookie = cookie;
+        ppm_save_bh = qemu_bh_new(qxl_render_ppm_save_bh, ppm_save_bh_data);
+        cookie->u.render.filename = g_strdup(filename);
+        cookie->u.render.ppm_save_bh = ppm_save_bh;
+        cookie->u.render.async = async;
+        cookie->u.render.cb = cb;
+        cookie->u.render.cb_opaque = cb_opaque;
+    }
     qxl_spice_update_area(qxl, 0, &cookie->u.render.area, NULL,
                           0, 1 /* clear_dirty_region */, QXL_ASYNC, cookie);
+    if (!async) {
+        dprint(qxl, 2, "warning: screendump saving possibly not up to date"
+                       "surface\n");
+        ppm_save(cookie->u.render.filename, qxl->ssd.ds->surface);
+    }
 }
 
 void qxl_render_update_area_bh(void *opaque)
@@ -187,10 +254,14 @@  void qxl_render_update_area_bh(void *opaque)
 void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie)
 {
     qemu_mutex_lock(&qxl->ssd.lock);
-    qemu_bh_schedule(qxl->update_area_bh);
-    qxl->render_update_cookie_num--;
+    if (cookie->u.render.filename) {
+        dprint(qxl, 1, "%s: scheduling ppm_save_bh\n", __func__);
+        qemu_bh_schedule(cookie->u.render.ppm_save_bh);
+    } else {
+        qemu_bh_schedule(qxl->update_area_bh);
+        qxl_cookie_render_free(qxl, cookie);
+    }
     qemu_mutex_unlock(&qxl->ssd.lock);
-    g_free(cookie);
 }
 
 static QEMUCursor *qxl_cursor(PCIQXLDevice *qxl, QXLCursor *cursor)
diff --git a/hw/qxl.c b/hw/qxl.c
index da0f931..48a7c4c 100644
--- a/hw/qxl.c
+++ b/hw/qxl.c
@@ -1477,7 +1477,7 @@  static void qxl_hw_update(void *opaque)
         break;
     case QXL_MODE_COMPAT:
     case QXL_MODE_NATIVE:
-        qxl_render_update(qxl);
+        qxl_render_update(qxl, NULL, false, NULL, NULL);
         break;
     default:
         break;
@@ -1492,7 +1492,10 @@  static void qxl_hw_invalidate(void *opaque)
     vga->invalidate(vga);
 }
 
-static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch)
+static void qxl_hw_screen_dump_helper(void *opaque, const char *filename,
+                                      bool cswitch, bool async,
+                                      vga_hw_screen_dump_async_cb_ptr cb,
+                                      void *cb_opaque)
 {
     PCIQXLDevice *qxl = opaque;
     VGACommonState *vga = &qxl->vga;
@@ -1500,17 +1503,38 @@  static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch)
     switch (qxl->mode) {
     case QXL_MODE_COMPAT:
     case QXL_MODE_NATIVE:
-        qxl_render_update(qxl);
-        ppm_save(filename, qxl->ssd.ds->surface);
+        qxl_render_update(qxl, filename, async, cb, cb_opaque);
         break;
     case QXL_MODE_VGA:
-        vga->screen_dump(vga, filename, cswitch);
+        if (async) {
+            if (vga->screen_dump_async) {
+                vga->screen_dump_async(vga, filename, cswitch, cb, cb_opaque);
+            } else {
+                vga->screen_dump(vga, filename, cswitch);
+                (*cb)(cb_opaque);
+            }
+        } else {
+            vga->screen_dump(vga, filename, cswitch);
+        }
         break;
     default:
         break;
     }
 }
 
+static void qxl_hw_screen_dump(void *opaque, const char *filename, bool cswitch)
+{
+    qxl_hw_screen_dump_helper(opaque, filename, cswitch, false, NULL, NULL);
+}
+
+static void qxl_hw_screen_dump_async(void *opaque, const char *filename,
+                                     bool cswitch,
+                                     vga_hw_screen_dump_async_cb_ptr cb,
+                                     void *cb_opaque)
+{
+    qxl_hw_screen_dump_helper(opaque, filename, cswitch, true, cb, cb_opaque);
+}
+
 static void qxl_hw_text_update(void *opaque, console_ch_t *chardata)
 {
     PCIQXLDevice *qxl = opaque;
@@ -1764,7 +1788,7 @@  static int qxl_init_primary(PCIDevice *dev)
 
     vga->ds = graphic_console_init(qxl_hw_update, qxl_hw_invalidate,
                                    qxl_hw_screen_dump, qxl_hw_text_update,
-                                   NULL, qxl);
+                                   qxl_hw_screen_dump_async, qxl);
     qemu_spice_display_init_common(&qxl->ssd, vga->ds);
 
     qxl0 = qxl;
diff --git a/hw/qxl.h b/hw/qxl.h
index 11a0db3..57c338c 100644
--- a/hw/qxl.h
+++ b/hw/qxl.h
@@ -147,7 +147,8 @@  void qxl_log_command(PCIQXLDevice *qxl, const char *ring, QXLCommandExt *ext);
 
 /* qxl-render.c */
 void qxl_render_resize(PCIQXLDevice *qxl);
-void qxl_render_update(PCIQXLDevice *qxl);
+void qxl_render_update(PCIQXLDevice *qxl, const char *filename, bool async,
+                       vga_hw_screen_dump_async_cb_ptr cb, void *cb_opaque);
 void qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext);
 void qxl_render_update_area_done(PCIQXLDevice *qxl, QXLCookie *cookie);
 void qxl_render_update_area_bh(void *opaque);
diff --git a/ui/spice-display.h b/ui/spice-display.h
index 12e50b6..7381b84 100644
--- a/ui/spice-display.h
+++ b/ui/spice-display.h
@@ -62,6 +62,11 @@  typedef struct QXLCookie {
         struct {
             QXLRect area;
             int redraw;
+            char *filename;
+            QEMUBH *ppm_save_bh;
+            bool async;
+            vga_hw_screen_dump_async_cb_ptr cb;
+            void *cb_opaque;
         } render;
     } u;
 } QXLCookie;