From bdf28d89dd6f47ca5b320b419fdc59e244bb5295 Mon Sep 17 00:00:00 2001 From: Volker Ruppert Date: Mon, 15 Oct 2012 19:43:06 +0000 Subject: [PATCH] Graphics snapshot handling for standard VGA and compatible modes (old graphics API) moved to the gui code. Splitted graphics_tile_update() in a common and a specific part. The common part handles the snapshot case if active. As a side effect, the snapshot feature now works for CGA modes, too. Fixed palette colors in 8 bpp snapshots. --- bochs/gui/gui.cc | 81 +++++++++++++++++++++++++++++----- bochs/gui/gui.h | 16 ++++--- bochs/iodev/display/vga.cc | 4 +- bochs/iodev/display/vgacore.cc | 60 ++++--------------------- 4 files changed, 91 insertions(+), 70 deletions(-) diff --git a/bochs/gui/gui.cc b/bochs/gui/gui.cc index 7de18146b..34c596524 100644 --- a/bochs/gui/gui.cc +++ b/bochs/gui/gui.cc @@ -103,6 +103,8 @@ bx_gui_c::bx_gui_c(void): disp_mode(DISP_MODE_SIM) guest_xres = 640; guest_yres = 480; guest_bpp = 8; + snapshot_mode = 0; + snapshot_buffer = NULL; memset(palette, 0, sizeof(palette)); } @@ -408,6 +410,29 @@ void bx_gui_c::make_text_snapshot(char **snapshot, Bit32u *length) *length = txt_addr; } +void bx_gui_c::set_snapshot_mode(bx_bool mode) +{ + unsigned pixel_bytes, bufsize; + + BX_GUI_THIS snapshot_mode = mode; + if (mode) { + pixel_bytes = ((BX_GUI_THIS guest_bpp + 1) >> 3); + bufsize = BX_GUI_THIS guest_xres * BX_GUI_THIS guest_yres * pixel_bytes; + BX_GUI_THIS snapshot_buffer = (Bit8u*)malloc(bufsize); + if (BX_GUI_THIS snapshot_buffer != NULL) { + memset(BX_GUI_THIS snapshot_buffer, 0, bufsize); + DEV_vga_redraw_area(0, 0, BX_GUI_THIS guest_xres, BX_GUI_THIS guest_yres); + DEV_vga_refresh(); + } + } else { + if (BX_GUI_THIS snapshot_buffer != NULL) { + free(BX_GUI_THIS snapshot_buffer); + BX_GUI_THIS snapshot_buffer = NULL; + DEV_vga_redraw_area(0, 0, BX_GUI_THIS guest_xres, BX_GUI_THIS guest_yres); + } + } +} + // create a text snapshot and copy to the system clipboard. On guis that // we haven't figured out how to support yet, dump to a file instead. void bx_gui_c::copy_handler(void) @@ -432,7 +457,7 @@ void bx_gui_c::copy_handler(void) // create a text snapshot and dump it to a file void bx_gui_c::snapshot_handler(void) { - int fd, i, j, mode, pitch; + int fd, i, j, pitch; Bit8u *snapshot_ptr = NULL; Bit8u *row_buffer, *pixel_ptr, *row_ptr; Bit8u bmp_header[54], iBits, b1, b2; @@ -466,16 +491,13 @@ void bx_gui_c::snapshot_handler(void) if (ilen > 0) { BX_INFO(("GFX snapshot: %u x %u x %u bpp (%u bytes)", BX_GUI_THIS guest_xres, BX_GUI_THIS guest_yres, BX_GUI_THIS guest_bpp, ilen)); - } else { - BX_ERROR(("snapshot button failed: cannot allocate memory")); - return; } if (BX_GUI_THIS dialog_caps & BX_GUI_DLG_SNAPSHOT) { int ret = SIM->ask_filename (filename, sizeof(filename), "Save snapshot as...", "snapshot.bmp", bx_param_string_c::SAVE_FILE_DIALOG); if (ret < 0) { // cancelled - free(snapshot_ptr); + if (snapshot_ptr != NULL) free(snapshot_ptr); return; } } else { @@ -489,9 +511,13 @@ void bx_gui_c::snapshot_handler(void) ); if (fd < 0) { BX_ERROR(("snapshot button failed: cannot create BMP file")); - free(snapshot_ptr); + if (snapshot_ptr != NULL) free(snapshot_ptr); return; } + if (ilen == 0) { + BX_GUI_THIS set_snapshot_mode(1); + snapshot_ptr = BX_GUI_THIS snapshot_buffer; + } iBits = (BX_GUI_THIS guest_bpp == 8) ? 8 : 24; rlen = (BX_GUI_THIS guest_xres * (iBits >> 3) + 3) & ~3; len = rlen * BX_GUI_THIS guest_yres + 54; @@ -518,7 +544,7 @@ void bx_gui_c::snapshot_handler(void) bmp_header[28] = iBits; write(fd, bmp_header, 54); if (BX_GUI_THIS guest_bpp == 8) { - write(fd, bx_gui->palette, 256 * 4); + write(fd, BX_GUI_THIS palette, 256 * 4); } pitch = BX_GUI_THIS guest_xres * ((BX_GUI_THIS guest_bpp + 1) >> 3); row_buffer = (Bit8u*)malloc(rlen); @@ -555,7 +581,11 @@ void bx_gui_c::snapshot_handler(void) } free(row_buffer); close(fd); - free(snapshot_ptr); + if (ilen > 0) { + free(snapshot_ptr); + } else { + BX_GUI_THIS set_snapshot_mode(0); + } } } @@ -925,11 +955,40 @@ void bx_gui_c::graphics_tile_update_in_place(unsigned x0, unsigned y0, delete [] tile; } +void bx_gui_c::graphics_tile_update_common(Bit8u *tile, unsigned x, unsigned y) +{ + unsigned i, pitch, pixel_bytes, nbytes, tilebytes; + Bit8u *src, *dst; + + if (BX_GUI_THIS snapshot_mode) { + if (BX_GUI_THIS snapshot_buffer != NULL) { + pixel_bytes = ((BX_GUI_THIS guest_bpp + 1) >> 3); + tilebytes = BX_GUI_THIS x_tilesize * pixel_bytes; + if ((x + BX_GUI_THIS x_tilesize) <= BX_GUI_THIS guest_xres) { + nbytes = tilebytes; + } else { + nbytes = (BX_GUI_THIS guest_xres - x) * pixel_bytes; + } + pitch = BX_GUI_THIS guest_xres * pixel_bytes; + src = tile; + dst = BX_GUI_THIS snapshot_buffer + (y * pitch) + x; + for (i = 0; i < y_tilesize; i++) { + memcpy(dst, src, nbytes); + src += tilebytes; + dst += pitch; + if (++y >= BX_GUI_THIS guest_yres) break; + } + } + } else { + graphics_tile_update(tile, x, y); + } +} + bx_bool bx_gui_c::palette_change_common(Bit8u index, Bit8u red, Bit8u green, Bit8u blue) { - palette[index].red = red; - palette[index].green = green; - palette[index].blue = blue; + BX_GUI_THIS palette[index].red = red; + BX_GUI_THIS palette[index].green = green; + BX_GUI_THIS palette[index].blue = blue; return palette_change(index, red, green, blue); } diff --git a/bochs/gui/gui.h b/bochs/gui/gui.h index 8fd34d011..8948a89bd 100644 --- a/bochs/gui/gui.h +++ b/bochs/gui/gui.h @@ -90,7 +90,7 @@ public: virtual void text_update(Bit8u *old_text, Bit8u *new_text, unsigned long cursor_x, unsigned long cursor_y, bx_vga_tminfo_t *tm_info) = 0; - virtual void graphics_tile_update(Bit8u *snapshot, unsigned x, unsigned y) = 0; + virtual void graphics_tile_update(Bit8u *tile, unsigned x, unsigned y) = 0; virtual bx_svga_tileinfo_t *graphics_tile_info(bx_svga_tileinfo_t *info); virtual Bit8u *graphics_tile_get(unsigned x, unsigned y, unsigned *w, unsigned *h); virtual void graphics_tile_update_in_place(unsigned x, unsigned y, unsigned w, unsigned h); @@ -143,6 +143,7 @@ public: void init(int argc, char **argv, unsigned max_xres, unsigned max_yres, unsigned x_tilesize, unsigned y_tilesize); void cleanup(void); + void graphics_tile_update_common(Bit8u *tile, unsigned x, unsigned y); bx_bool palette_change_common(Bit8u index, Bit8u red, Bit8u green, Bit8u blue); void update_drive_status_buttons(void); static void mouse_enabled_changed(bx_bool val); @@ -170,8 +171,9 @@ protected: static void config_handler(void); static void userbutton_handler(void); static void save_restore_handler(void); - // text snapshot helper function + // snapshot helper functions static void make_text_snapshot(char **snapshot, Bit32u *length); + static void set_snapshot_mode(bx_bool mode); // status bar LED timer static void led_timer_handler(void *); void led_timer(void); @@ -225,11 +227,13 @@ protected: unsigned guest_xres; unsigned guest_yres; unsigned guest_bpp; - // current palette (for graphics snapshot + // graphics snapshot + bx_bool snapshot_mode; + Bit8u *snapshot_buffer; struct { - Bit8u red; - Bit8u green; Bit8u blue; + Bit8u green; + Bit8u red; Bit8u reserved; } palette[256]; // mouse toggle setup @@ -256,7 +260,7 @@ virtual void specific_init(int argc, char **argv, \ virtual void text_update(Bit8u *old_text, Bit8u *new_text, \ unsigned long cursor_x, unsigned long cursor_y, \ bx_vga_tminfo_t *tm_info); \ -virtual void graphics_tile_update(Bit8u *snapshot, unsigned x, unsigned y); \ +virtual void graphics_tile_update(Bit8u *tile, unsigned x, unsigned y); \ virtual void handle_events(void); \ virtual void flush(void); \ virtual void clear_screen(void); \ diff --git a/bochs/iodev/display/vga.cc b/bochs/iodev/display/vga.cc index 7fdd39053..b3da21794 100644 --- a/bochs/iodev/display/vga.cc +++ b/bochs/iodev/display/vga.cc @@ -677,7 +677,7 @@ void bx_vga_c::update(void) } } SET_TILE_UPDATED (xti, yti, 0); - bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc); + bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc); } } } @@ -767,7 +767,7 @@ void bx_vga_c::mem_write(bx_phy_address addr, Bit8u value) Bit32u bx_vga_c::get_gfx_snapshot(Bit8u **snapshot_ptr) { Bit32u len, len1; - unsigned i, shift; + unsigned i; Bit8u *dst_ptr, *src_ptr; if ((BX_VGA_THIS vbe.enabled) && (BX_VGA_THIS vbe.bpp >= 8)) { diff --git a/bochs/iodev/display/vgacore.cc b/bochs/iodev/display/vgacore.cc index 8ae63f78e..abac5da1e 100644 --- a/bochs/iodev/display/vgacore.cc +++ b/bochs/iodev/display/vgacore.cc @@ -1496,7 +1496,7 @@ void bx_vgacore_c::update(void) } } SET_TILE_UPDATED (xti, yti, 0); - bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc); + bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc); } } } @@ -1523,7 +1523,7 @@ void bx_vgacore_c::update(void) } } SET_TILE_UPDATED (xti, yti, 0); - bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc); + bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc); } } } @@ -1560,7 +1560,7 @@ void bx_vgacore_c::update(void) } } SET_TILE_UPDATED (xti, yti, 0); - bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc); + bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc); } } } @@ -1594,7 +1594,7 @@ void bx_vgacore_c::update(void) } } SET_TILE_UPDATED (xti, yti, 0); - bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc); + bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc); } } } @@ -1618,7 +1618,7 @@ void bx_vgacore_c::update(void) } } SET_TILE_UPDATED (xti, yti, 0); - bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc); + bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc); } } } @@ -1642,7 +1642,7 @@ void bx_vgacore_c::update(void) } } SET_TILE_UPDATED (xti, yti, 0); - bx_gui->graphics_tile_update(BX_VGA_THIS s.tile, xc, yc); + bx_gui->graphics_tile_update_common(BX_VGA_THIS s.tile, xc, yc); } } } @@ -2302,51 +2302,9 @@ void bx_vgacore_c::get_text_snapshot(Bit8u **text_snapshot, unsigned *txHeight, Bit32u bx_vgacore_c::get_gfx_snapshot(Bit8u **snapshot_ptr) { - Bit32u len; - unsigned line_compare, start_addr, x, y; - unsigned byte_offset, px, py; - Bit8u *dst_ptr, *plane[4]; - - len = (BX_VGA_THIS s.last_xres * BX_VGA_THIS s.last_yres); - *snapshot_ptr = (Bit8u*)malloc(len); - if (snapshot_ptr == NULL) - return 0; - dst_ptr = *snapshot_ptr; - plane[0] = &BX_VGA_THIS s.memory[0 << BX_VGA_THIS s.plane_shift]; - plane[1] = &BX_VGA_THIS s.memory[1 << BX_VGA_THIS s.plane_shift]; - plane[2] = &BX_VGA_THIS s.memory[2 << BX_VGA_THIS s.plane_shift]; - plane[3] = &BX_VGA_THIS s.memory[3 << BX_VGA_THIS s.plane_shift]; - start_addr = (BX_VGA_THIS s.CRTC.reg[0x0c] << 8) | BX_VGA_THIS s.CRTC.reg[0x0d]; - line_compare = BX_VGA_THIS s.line_compare; - if (BX_VGA_THIS s.y_doublescan) line_compare >>= 1; - if ((BX_VGA_THIS s.graphics_ctrl.shift_reg == 0) && - (BX_VGA_THIS s.graphics_ctrl.memory_mapping != 3)) { - for (y = 0; y < BX_VGA_THIS s.last_yres; y++) { - for (x = 0; x < BX_VGA_THIS s.last_xres; x++) { - *(dst_ptr++) = BX_VGA_THIS get_vga_pixel(x, y, start_addr, line_compare, 0, plane); - } - } - return len; - } else if (BX_VGA_THIS s.graphics_ctrl.shift_reg == 2) { - for (y = 0; y < BX_VGA_THIS s.last_yres; y++) { - for (x = 0; x < BX_VGA_THIS s.last_xres; x++) { - px = x >> 1; - py = y >> BX_VGA_THIS s.y_doublescan; - byte_offset = start_addr + py * BX_VGA_THIS s.line_offset; - if (BX_VGA_THIS s.CRTC.reg[0x14] & 0x40) { // DW set: doubleword mode - byte_offset += (px & ~0x03); - } else if (BX_VGA_THIS s.CRTC.reg[0x17] & 0x40) { // B/W set: byte mode, modeX - byte_offset += (px >> 2); - } else { - byte_offset += (px >> 1) & ~0x01; - } - *(dst_ptr++) = plane[px % 4][byte_offset]; - } - } - return len; - } else { - return 0; - } + // handled in the gui code + *snapshot_ptr = NULL; + return 0; } #if BX_DEBUGGER