]> xenbits.xensource.com Git - xenclient/ioemu.git/commitdiff
Add screenshot support for intel and emulated graphic card.
authorJean Guyader <jean.guyader@eu.citrix.com>
Fri, 21 Nov 2008 12:35:38 +0000 (12:35 +0000)
committerJean Guyader <jean.guyader@eu.citrix.com>
Fri, 21 Nov 2008 12:35:38 +0000 (12:35 +0000)
  Write the file into xenstore at /local/domain/domid/screenshot.
  "done" is written when the screenshot is ready.

  The screenshot is a binary ppm file.

console.h
dom0_driver.c
hw/vga.c
intel.c
qemu-xen.h
vl.c
xen-config-host.h
xenstore.c

index 67ce1d9a2944d8920b890a8545877bb30c11f034..bcd0b00372717993c4ef0cd6463789e065db995d 100644 (file)
--- a/console.h
+++ b/console.h
@@ -120,6 +120,7 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
 void vga_hw_update(void);
 void vga_hw_invalidate(void);
 void vga_hw_screen_dump(const char *filename);
+void vga_take_screenshot(const char *filename, DisplayState *ds);
 
 int is_graphic_console(void);
 CharDriverState *text_console_init(DisplayState *ds, const char *p);
@@ -172,5 +173,6 @@ void dom0_driver_init(const char *position);
 /* intel.c */
 void intel_display_init(DisplayState *ds, const char *arg);
 void intel_focus(int focus);
+void intel_take_screenshot(const char *filename);
 
 #endif
index 07b35c072f23f5087a206c2672fe1012e16677f3..4291f00ee10892d110af83d0bbfa57e1dd8ea64e 100644 (file)
@@ -396,7 +396,8 @@ static void dom0_gr_devices(int grab, int controller)
             struct dom0_driver_xs_info  info;
 
             dom0_driver_read_xs_info(&info, DOM0_MOUSE);
-            if (dom0_driver_xs_read_dom0("natif") != info.domid)
+            if (!vga_passthrough &&
+                dom0_driver_xs_read_dom0("natif") != info.domid)
                 intel_focus(!grab);
         }
     }
@@ -568,7 +569,8 @@ static void dom0_driver_blank_done(void)
     if (info.state == 1 && blank == 2)
     {
         sleep(1);
-        intel_focus(info.domid == domid);
+        if (!vga_passthrough)
+            intel_focus(info.domid == domid);
     }
 }
 
index c843821cb1f3c0050df62c0bd082dce2b5c93f56..e59880659aa65a779d45809085034e7fa3e37756 100644 (file)
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2424,3 +2424,8 @@ static void vga_screen_dump(void *opaque, const char *filename)
     }
     s->ds = saved_ds;
 }
+
+void vga_take_screenshot(const char *filename, DisplayState *ds)
+{
+    ppm_save(filename, ds->data, ds->width, ds->height, ds->linesize);
+}
diff --git a/intel.c b/intel.c
index cd074c713a7f6d1d70809a53783215c06d18c9e2..25ae423fdd2fa8be519a6618c7f07a832276b048 100644 (file)
--- a/intel.c
+++ b/intel.c
 
 #define TileW           128
 #define TileH           8
-#define TilePitch       16
 
-#define REG_DR_DSPASURF 0x7019C
-#define REG_DR_DSPACNTR 0x70180
+#define REG_DR_DSPASURF         0x7019C
+#define REG_DR_DSPACNTR         0x70180
+#define REG_DR_DSPASTRIDE       0x70188
+
+extern int                      vga_passthrough;
 
 static int                      display = 0;
 
@@ -32,6 +34,9 @@ static int                      intel_force_full_update = 0;
 static int                      intel_have_focus;
 static int                      solid_line[8];
 static int                      dashed_line[8];
+static int                      TilePitch = 16;
+static int                      TileX = 1280;
+static int                      TileY = 1024;
 static DisplayState             *lds = NULL;
 
 static inline unsigned int intel_get_reg(unsigned int reg)
@@ -49,11 +54,26 @@ static inline unsigned int intel_get_offset(DisplayState *ds, int x, int y)
     return (y * ds->width + x) * 4;
 }
 
-static inline void intel_blit_tile(DisplayState *ds, int x, int y)
+static inline void intel_blit_tile(DisplayState *ds, int read, int x, int y)
 {
+    typedef void (*copy_fptr) (uint8_t *, uint8_t *, int);
+    void        copy_read(uint8_t *tbuff, uint8_t *buff, int size)
+    {
+        memcpy(buff, tbuff, size);
+    }
+    void        copy_write(uint8_t *tbuff, uint8_t *buff, int size)
+    {
+        memcpy(tbuff, buff, size);
+    }
     unsigned int        toffset, offset, to, o;
     unsigned char       *buff;
     int                 i, j;
+    copy_fptr           copy = NULL;
+
+    if (read)
+        copy = copy_read;
+    else
+        copy = copy_write;
 
     buff = (unsigned char *)(intel_mem + intel_get_reg(REG_DR_DSPASURF));
 
@@ -64,7 +84,7 @@ static inline void intel_blit_tile(DisplayState *ds, int x, int y)
     {
         to = toffset + solid_line[i] * TileW * 4;
         o = offset + solid_line[i] * ds->width * 4;
-        memcpy(&buff[to], &ds->data[o], TileW * 4);
+        copy(&buff[to], &ds->data[o], TileW * 4);
     }
 
     toffset = to = intel_get_tiled_offset(x, y);
@@ -75,10 +95,10 @@ static inline void intel_blit_tile(DisplayState *ds, int x, int y)
         o = offset + dashed_line[i] * ds->width * 4 + 16 * 4;
         for (j = 0; j < 4 ; j++)
         {
-            memcpy(&buff[to], &ds->data[o], 16 * 4);
+            copy(&buff[to], &ds->data[o], 16 * 4);
             to += 16 * 4;
             o -= 16 * 4;
-            memcpy(&buff[to], &ds->data[o], 16 * 4);
+            copy(&buff[to], &ds->data[o], 16 * 4);
             to += 16 * 4;
             o += 48 * 4;
         }
@@ -97,9 +117,9 @@ static void intel_update_tiled(DisplayState *ds, int x, int y, int w, int h)
 
     for (i = yt; i < ht; i++)
         for (j = xt; j < wt; j++)
-            if (j >= 0 && j < 10 && i >= 0 && i < 100 &&
+            if (j >= 0 && j < (TileX / TileW) && i >= 0 && i < (TileY / TileH) &&
                 (i * TileH) < ds->height && (j * TileW) < ds->width)
-                intel_blit_tile(ds, j, i);
+                intel_blit_tile(ds, 0, j, i);
 }
 
 static void intel_update(DisplayState *ds, int x, int y, int w, int h)
@@ -118,6 +138,19 @@ static void intel_resize(DisplayState *ds, int w, int h)
 
 static void intel_refresh(DisplayState *ds)
 {
+    if (intel_get_reg(REG_DR_DSPASTRIDE) == 0x1000)
+    {
+        TilePitch = 8;
+        TileX = 1024;
+        TileY = 768;
+    }
+    else
+    {
+        TilePitch = 16;
+        TileX = 1280;
+        TileY = 800;
+    }
+
     vga_hw_update();
 }
 
@@ -183,7 +216,7 @@ static void intel_parse_arg(const char *arg)
     tab = solid_line;
     while (arg && *arg)
     {
-        tab[0] = strtol(arg, next, 10);
+        tab[0] = strtol(arg, &next, 10);
         tab[1] = -1;
         INTEL_DEBUG("solid/dashed line %d\n", *tab);
         if (!next || !*next)
@@ -197,22 +230,67 @@ static void intel_parse_arg(const char *arg)
             INTEL_DEBUG("unknow separator %c for intel arguement\n", *next);
             exit (2);
         }
+        arg = next + 1;
     }
 }
 
+void intel_take_screenshot(const char *filename)
+{
+    int                 i,j = 0;
+    FILE                *fd;
+    struct DisplayState ds;
+    uint8_t             *d;
+    uint32_t            p;
+    
+    INTEL_DEBUG("Take a screenshot %s\n", filename);
+    
+    intel_refresh(&ds);
+
+    fd = fopen(filename, "w");
+    fprintf(fd, "P6\n%d %d\n%d\n", TileX, TileY, 255);
+    INTEL_DEBUG("screenshot %d,%d\n", TileX, TileY);
+
+    ds.width = TileX;
+    ds.height = TileY;
+    ds.linesize = 4 * ds.width;
+    ds.depth = 32;
+    ds.data = malloc(ds.height * ds.linesize);
+    memset(ds.data, 0, ds.height * ds.linesize);
+
+    for (j = 0; j < TileY / TileH; j++)
+        for (i = 0; i < TileX / TileW; i++)
+            intel_blit_tile(&ds, 1, i, j);
+
+    d = ds.data;
+    for (j = 0; j < TileY; j++)
+        for (i = 0; i < TileX; i++)
+        {
+            p = *(uint32_t *)d;
+            fputc((p >> 16) & 0xff, fd);
+            fputc((p >> 8) & 0xff, fd);
+            fputc((p) & 0xff, fd);
+            d += 4;
+        }
+    fclose(fd);
+}
+
 void intel_display_init(DisplayState *ds, const char *arg)
 {
+    INTEL_DEBUG("\n");
+
+    xenstore_watch_screenshot_node();
+
     intel_parse_arg(arg);
     intel_init_mapping();
 
     INTEL_DEBUG("Frambuffer is at 0x%x\n", intel_get_reg(REG_DR_DSPASURF));
 
     ds->shared_buf = 0;
-    ds->data =  NULL;
     ds->width = 640;
     ds->height = 400;
     ds->linesize = 640 * 4;
     ds->depth = 32;
+    ds->data =  malloc(ds->height * ds->linesize);
     lds = ds;
 
     ds->dpy_update = intel_update;
index bb9eb1727f1bfd7cceaf5658ce3130c8fa69593b..03ce13b0044c4705d475fbd8f87fcc6ede275357 100644 (file)
@@ -44,8 +44,9 @@ void handle_buffered_pio(void);
 #endif
 
 /* xenstore.c */
-typedef void (*xenstore_callback) (const char *token);
-void xenstore_watch_callback(const char *token, xenstore_callback fptr);
+typedef void (*xenstore_callback) (const char *token, void *opaque);
+int xenstore_watch_screenshot_node(DisplayState *ds);
+void xenstore_watch_callback(const char *token, xenstore_callback fptr, void *opaque);
 void xenstore_parse_domain_config(int domid);
 int xenstore_fd(void);
 void xenstore_process_event(void *opaque);
diff --git a/vl.c b/vl.c
index b14b03b946e2bf44258febee0b0e6fb4e657c780..9491b070f68c3b6ac10f53dce5962beb15700774 100644 (file)
--- a/vl.c
+++ b/vl.c
@@ -7651,7 +7651,7 @@ const QEMUOption qemu_options[] = {
     { "localtime", 0, QEMU_OPTION_localtime },
     { "std-vga", 0, QEMU_OPTION_std_vga },
     { "videoram", HAS_ARG, QEMU_OPTION_videoram },
-    { "intel", 0, QEMU_OPTION_intel },
+    { "intel", HAS_ARG, QEMU_OPTION_intel },
     { "echr", HAS_ARG, QEMU_OPTION_echr },
     { "monitor", HAS_ARG, QEMU_OPTION_monitor },
     { "domain-name", 1, QEMU_OPTION_domainname },
@@ -8826,6 +8826,8 @@ int main(int argc, char **argv)
     /* terminal init */
     memset(&display_state, 0, sizeof(display_state));
 
+    xenstore_watch_screenshot_node(&display_state);
+
 #ifdef CONFIG_STUBDOM
     if (xenfb_pv_display_init(ds) == 0) {
     } else
index 4ad1eb7b9eafd2933f8733f38e6235e5e5451723..e8782d543e6654e28ccfa6801c55dd92d0f824f2 100644 (file)
@@ -49,7 +49,7 @@ void xenstore_store_serial_port_info(int i, struct CharDriverState *chr,
 char *xenstore_read_dom0_driver(const char *key);
 int xenstore_write_dom0_driver(const char *key, int val);
 
-char *xenstore_dom_read(int domid, char *key, unsigned long *len);
+char *xenstore_dom_read(int domid, char *key, unsigned int *len);
 int xenstore_dom_write(int domid, char *key, char *value);
 
 int *xenstore_get_domids(int *len);
index 485e9cde7ead424b735af62be02d9343a8595347..1f0655513719729f4a49ae530f7e9f77aa2070c4 100644 (file)
@@ -30,6 +30,9 @@
 #include "pc.h"
 #include "qemu-timer.h"
 #include "qemu-xen.h"
+#include "console.h"
+
+extern int vga_passthrough;
 
 struct xs_handle *xsh = NULL;
 static char *media_filename[MAX_DRIVES+1];
@@ -42,11 +45,12 @@ struct xenstore_watch_cb_t
 {
     char                *token;
     xenstore_callback   cb;
+    void                *opaque;
 };
 
 static struct xenstore_watch_cb_t *xenstore_watch_callbacks = NULL;
 
-void xenstore_watch_callback(const char *token, xenstore_callback fptr)
+void xenstore_watch_callback(const char *token, xenstore_callback fptr, void *opaque)
 {
     int         i = 0;
 
@@ -63,6 +67,7 @@ void xenstore_watch_callback(const char *token, xenstore_callback fptr)
                                        (i + 2) * sizeof (struct xenstore_watch_cb_t));
     xenstore_watch_callbacks[i].token = strdup(token);
     xenstore_watch_callbacks[i].cb = fptr;
+    xenstore_watch_callbacks[i].opaque = opaque;
     xenstore_watch_callbacks[i + 1].token = NULL;
 }
 
@@ -824,9 +829,10 @@ void xenstore_process_event(void *opaque)
     if (!vec)
         return;
 
-    for (i = 0; xenstore_watch_callbacks[i].token; i++)
+    for (i = 0; xenstore_watch_callbacks &&  xenstore_watch_callbacks[i].token; i++)
         if (!strcmp(vec[XS_WATCH_TOKEN], xenstore_watch_callbacks[i].token))
-            xenstore_watch_callbacks[i].cb(vec[XS_WATCH_TOKEN]);
+            xenstore_watch_callbacks[i].cb(vec[XS_WATCH_TOKEN],
+                                           xenstore_watch_callbacks[i].opaque);
 
     if (!strcmp(vec[XS_WATCH_TOKEN], "logdirty")) {
         xenstore_process_logdirty_event();
@@ -1440,7 +1446,7 @@ int xenstore_write_dom0_driver(const char *key, int val)
     return ret;
 }
 
-char *xenstore_dom_read(int domid, char *key, unsigned long *len)
+char *xenstore_dom_read(int domid, char *key, unsigned int *len)
 {
     char *buf = NULL, *path = NULL, *value = NULL;
 
@@ -1534,3 +1540,54 @@ void xenstore_dm_finished_startup(void)
     free(buf);
     free(path);
 }
+
+void xenstore_screenshot(const char *token, void *opaque)
+{
+    char                *filename;
+    unsigned int        len;
+    DisplayState        *ds = (DisplayState *)opaque;
+
+    filename = xenstore_dom_read(domid, "screenshot", &len);
+    if (!filename)
+        return;
+
+    if (!strcmp(filename, "done"))
+    {
+        free(filename);
+        return;
+    }
+
+    fprintf(stderr, "screenshot %s\n", filename);
+
+    if (vga_passthrough)
+        intel_take_screenshot(filename);
+    else
+        vga_take_screenshot(filename, ds);
+
+    free(filename);
+    xenstore_dom_write(domid, "screenshot", "done");
+}
+
+int xenstore_watch_screenshot_node(DisplayState *ds)
+{
+    char *path;
+    char *buf = NULL;
+    int ret = 0;
+
+    path = xs_get_domain_path(xsh, domid);
+    if (!path) {
+        fprintf(logfile, "xs_get_domain_path() failed.\n");
+        goto out;
+    }
+    if (pasprintf(&buf, "%s/screenshot", path) == -1) {
+        fprintf(logfile, "pasprintf failed to get path.\n");
+        goto out;
+    }
+    xenstore_watch_callback("screenshot", xenstore_screenshot, ds);
+    fprintf(stderr, "screenshot watch node %s\n", buf);
+    ret = xs_watch(xsh, buf, "screenshot");
+ out:
+    free(buf);
+    free(path);
+    return ret;
+}