From: Jean Guyader Date: Fri, 21 Nov 2008 12:35:38 +0000 (+0000) Subject: Add screenshot support for intel and emulated graphic card. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=4a0522b3f1de9da682ee5c47c76f0b76ea0213a4;p=xenclient%2Fioemu.git Add screenshot support for intel and emulated graphic card. 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. --- diff --git a/console.h b/console.h index 67ce1d9a..bcd0b003 100644 --- 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 diff --git a/dom0_driver.c b/dom0_driver.c index 07b35c07..4291f00e 100644 --- a/dom0_driver.c +++ b/dom0_driver.c @@ -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); } } diff --git a/hw/vga.c b/hw/vga.c index c843821c..e5988065 100644 --- 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 cd074c71..25ae423f 100644 --- a/intel.c +++ b/intel.c @@ -17,10 +17,12 @@ #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; diff --git a/qemu-xen.h b/qemu-xen.h index bb9eb172..03ce13b0 100644 --- a/qemu-xen.h +++ b/qemu-xen.h @@ -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 b14b03b9..9491b070 100644 --- 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 diff --git a/xen-config-host.h b/xen-config-host.h index 4ad1eb7b..e8782d54 100644 --- a/xen-config-host.h +++ b/xen-config-host.h @@ -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); diff --git a/xenstore.c b/xenstore.c index 485e9cde..1f065551 100644 --- a/xenstore.c +++ b/xenstore.c @@ -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; +}