diff --git a/src/86box.c b/src/86box.c index 148eb63f8..24f74b04a 100644 --- a/src/86box.c +++ b/src/86box.c @@ -139,10 +139,6 @@ char log_path[1024] = { '\0'}; /* (O) full path of logfile */ char vm_name[1024] = { '\0'}; /* (O) display name of the VM */ /* Configuration values. */ -int window_w; /* (C) window size and */ -int window_h; /* position info */ -int window_x; -int window_y; int window_remember; int vid_resize; /* (C) allow resizing */ int invert_display = 0; /* (C) invert the display */ @@ -166,6 +162,8 @@ int postcard_enabled = 0; /* (C) enable POST card */ int isamem_type[ISAMEM_MAX] = { 0,0,0,0 }; /* (C) enable ISA mem cards */ int isartc_type = 0; /* (C) enable ISA RTC card */ int gfxcard = 0; /* (C) graphics/video card */ +int gfxcard_2 = 0; /* (C) graphics/video card */ +int show_second_monitors = 1; /* (C) show non-primary monitors */ int sound_is_float = 1; /* (C) sound uses FP values */ int GAMEBLASTER = 0; /* (C) sound option */ int GUS = 0; /* (C) sound option */ @@ -201,17 +199,17 @@ char exe_path[2048]; /* path (dir) of executable */ char usr_path[1024]; /* path (dir) of user data */ char cfg_path[1024]; /* full path of config file */ FILE *stdlog = NULL; /* file to log output to */ -int scrnsz_x = SCREEN_RES_X; /* current screen size, X */ -int scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ +//int scrnsz_x = SCREEN_RES_X; /* current screen size, X */ +//int scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ int config_changed; /* config has changed */ int title_update; int framecountx = 0; int hard_reset_pending = 0; -int unscaled_size_x = SCREEN_RES_X; /* current unscaled size X */ -int unscaled_size_y = SCREEN_RES_Y; /* current unscaled size Y */ -int efscrnsz_y = SCREEN_RES_Y; +//int unscaled_size_x = SCREEN_RES_X; /* current unscaled size X */ +//int unscaled_size_y = SCREEN_RES_Y; /* current unscaled size Y */ +//int efscrnsz_y = SCREEN_RES_Y; static wchar_t mouse_msg[3][200]; @@ -855,6 +853,15 @@ pc_init_modules(void) } } + if (! video_card_available(gfxcard_2)) { + char temp[1024] = { 0 }; + char tempc[1024] = { 0 }; + device_get_name(video_card_getdevice(gfxcard_2), 0, tempc); + snprintf(temp, sizeof(temp), "Video card #2 \"%s\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card.", tempc); + ui_msgbox_header(MBX_INFO, (wchar_t *) IDS_2128, temp); + gfxcard_2 = 0; + } + atfullspeed = 0; random_init(); @@ -1250,14 +1257,13 @@ pc_onesec(void) title_update = 1; } - void -set_screen_size(int x, int y) +set_screen_size_monitor(int x, int y, int monitor_index) { - int owsx = scrnsz_x; - int owsy = scrnsz_y; - int temp_overscan_x = overscan_x; - int temp_overscan_y = overscan_y; + int owsx = monitors[monitor_index].mon_scrnsz_x; + int owsy = monitors[monitor_index].mon_scrnsz_y; + int temp_overscan_x = monitors[monitor_index].mon_overscan_x; + int temp_overscan_y = monitors[monitor_index].mon_overscan_y; double dx, dy, dtx, dty; /* Make sure we keep usable values. */ @@ -1270,78 +1276,89 @@ set_screen_size(int x, int y) if (y > 2048) y = 2048; /* Save the new values as "real" (unscaled) resolution. */ - unscaled_size_x = x; - efscrnsz_y = y; + monitors[monitor_index].mon_unscaled_size_x = x; + monitors[monitor_index].mon_efscrnsz_y = y; if (suppress_overscan) - temp_overscan_x = temp_overscan_y = 0; + temp_overscan_x = temp_overscan_y = 0; if (force_43) { - dx = (double)x; - dtx = (double)temp_overscan_x; + dx = (double)x; + dtx = (double)temp_overscan_x; - dy = (double)y; - dty = (double)temp_overscan_y; + dy = (double)y; + dty = (double)temp_overscan_y; - /* Account for possible overscan. */ - if (!(video_is_ega_vga()) && (temp_overscan_y == 16)) { - /* CGA */ - dy = (((dx - dtx) / 4.0) * 3.0) + dty; - } else if (!(video_is_ega_vga()) && (temp_overscan_y < 16)) { - /* MDA/Hercules */ - dy = (x / 4.0) * 3.0; - } else { - if (enable_overscan) { - /* EGA/(S)VGA with overscan */ - dy = (((dx - dtx) / 4.0) * 3.0) + dty; - } else { - /* EGA/(S)VGA without overscan */ - dy = (x / 4.0) * 3.0; - } - } - unscaled_size_y = (int)dy; + /* Account for possible overscan. */ + if (video_get_type_monitor(monitor_index) != VIDEO_FLAG_TYPE_SPECIAL && (temp_overscan_y == 16)) { + /* CGA */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else if (video_get_type_monitor(monitor_index) != VIDEO_FLAG_TYPE_SPECIAL && (temp_overscan_y < 16)) { + /* MDA/Hercules */ + dy = (x / 4.0) * 3.0; + } else { + if (enable_overscan) { + /* EGA/(S)VGA with overscan */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else { + /* EGA/(S)VGA without overscan */ + dy = (x / 4.0) * 3.0; + } + } + monitors[monitor_index].mon_unscaled_size_y = (int)dy; } else - unscaled_size_y = efscrnsz_y; + monitors[monitor_index].mon_unscaled_size_y = monitors[monitor_index].mon_efscrnsz_y; switch(scale) { - case 0: /* 50% */ - scrnsz_x = (unscaled_size_x>>1); - scrnsz_y = (unscaled_size_y>>1); - break; + case 0: /* 50% */ + monitors[monitor_index].mon_scrnsz_x = (monitors[monitor_index].mon_unscaled_size_x>>1); + monitors[monitor_index].mon_scrnsz_y = (monitors[monitor_index].mon_unscaled_size_y>>1); + break; - case 1: /* 100% */ - scrnsz_x = unscaled_size_x; - scrnsz_y = unscaled_size_y; - break; + case 1: /* 100% */ + monitors[monitor_index].mon_scrnsz_x = monitors[monitor_index].mon_unscaled_size_x; + monitors[monitor_index].mon_scrnsz_y = monitors[monitor_index].mon_unscaled_size_y; + break; - case 2: /* 150% */ - scrnsz_x = ((unscaled_size_x*3)>>1); - scrnsz_y = ((unscaled_size_y*3)>>1); - break; + case 2: /* 150% */ + monitors[monitor_index].mon_scrnsz_x = ((monitors[monitor_index].mon_unscaled_size_x*3)>>1); + monitors[monitor_index].mon_scrnsz_y = ((monitors[monitor_index].mon_unscaled_size_y*3)>>1); + break; - case 3: /* 200% */ - scrnsz_x = (unscaled_size_x<<1); - scrnsz_y = (unscaled_size_y<<1); - break; + case 3: /* 200% */ + monitors[monitor_index].mon_scrnsz_x = (monitors[monitor_index].mon_unscaled_size_x<<1); + monitors[monitor_index].mon_scrnsz_y = (monitors[monitor_index].mon_unscaled_size_y<<1); + break; } - /* If the resolution has changed, let the main thread handle it. */ - if ((owsx != scrnsz_x) || (owsy != scrnsz_y)) - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[monitor_index], 1); } +void +set_screen_size(int x, int y) +{ + set_screen_size_monitor(x, y, monitor_index_global); +} + +void +reset_screen_size_monitor(int monitor_index) +{ + set_screen_size(monitors[monitor_index].mon_unscaled_size_x, monitors[monitor_index].mon_efscrnsz_y); +} void reset_screen_size(void) { - set_screen_size(unscaled_size_x, efscrnsz_y); + for (int i = 0; i < MONITORS_NUM; i++) + set_screen_size(monitors[i].mon_unscaled_size_x, monitors[i].mon_efscrnsz_y); } void set_screen_size_natural(void) { - set_screen_size(unscaled_size_x, unscaled_size_y); + for (int i = 0; i < MONITORS_NUM; i++) + set_screen_size(monitors[i].mon_unscaled_size_x, monitors[i].mon_unscaled_size_y); } diff --git a/src/config.c b/src/config.c index ca14b567a..eea247e3f 100644 --- a/src/config.c +++ b/src/config.c @@ -552,14 +552,8 @@ load_general(void) if (window_remember || (vid_resize & 2)) { if (!window_remember) config_delete_var(cat, "window_remember"); - - p = config_get_string(cat, "window_coordinates", NULL); - if (p == NULL) - p = "0, 0, 0, 0"; - sscanf(p, "%i, %i, %i, %i", &window_w, &window_h, &window_x, &window_y); } else { config_delete_var(cat, "window_remember"); - config_delete_var(cat, "window_coordinates"); window_w = window_h = window_x = window_y = 0; } @@ -932,6 +926,49 @@ load_video(void) voodoo_enabled = !!config_get_int(cat, "voodoo", 0); ibm8514_enabled = !!config_get_int(cat, "8514a", 0); xga_enabled = !!config_get_int(cat, "xga", 0); + show_second_monitors = !!config_get_int(cat, "show_second_monitors", 1); + p = config_get_string(cat, "gfxcard_2", NULL); + if (!p) p = "none"; + gfxcard_2 = video_get_video_from_internal_name(p); +} + + +static void +load_monitor(int monitor_index) +{ + char monitor_config_name[sizeof("Monitor #") + 12] = { [0] = 0 }; + char* ptr = NULL; + + if (monitor_index == 0) { + /* Migrate configs */ + ptr = config_get_string("General", "window_coordinates", NULL); + + config_delete_var("General", "window_coordinates"); + } + snprintf(monitor_config_name, sizeof(monitor_config_name), "Monitor #%i", monitor_index + 1); + if (!ptr) ptr = config_get_string(monitor_config_name, "window_coordinates", "0, 0, 0, 0"); + if (window_remember || (vid_resize & 2)) sscanf(ptr, "%i, %i, %i, %i", + &monitor_settings[monitor_index].mon_window_x, &monitor_settings[monitor_index].mon_window_y, + &monitor_settings[monitor_index].mon_window_w, &monitor_settings[monitor_index].mon_window_h); +} + +static void +save_monitor(int monitor_index) +{ + char monitor_config_name[sizeof("Monitor #") + 12] = { [0] = 0 }; + char saved_coordinates[12 * 4 + 8 + 1] = { [0] = 0 }; + + snprintf(monitor_config_name, sizeof(monitor_config_name), "Monitor #%i", monitor_index + 1); + if (!(monitor_settings[monitor_index].mon_window_x == 0 + && monitor_settings[monitor_index].mon_window_y == 0 + && monitor_settings[monitor_index].mon_window_w == 0 + && monitor_settings[monitor_index].mon_window_h == 0) && (window_remember || (vid_resize & 2))) { + snprintf(saved_coordinates, sizeof(saved_coordinates), "%i, %i, %i, %i", monitor_settings[monitor_index].mon_window_x, monitor_settings[monitor_index].mon_window_y, + monitor_settings[monitor_index].mon_window_w, monitor_settings[monitor_index].mon_window_h); + + config_set_string(monitor_config_name, "window_coordinates", saved_coordinates); + } + else config_delete_var(monitor_config_name, "window_coordinates"); } @@ -2156,6 +2193,8 @@ config_load(void) config_log("Config file not present or invalid!\n"); } else { load_general(); /* General */ + for (i = 0; i < MONITORS_NUM; i++) + load_monitor(i); load_machine(); /* Machine */ load_video(); /* Video */ load_input_devices(); /* Input devices */ @@ -2265,12 +2304,8 @@ save_general(void) config_set_int(cat, "window_remember", window_remember); else config_delete_var(cat, "window_remember"); - - sprintf(temp, "%i, %i, %i, %i", window_w, window_h, window_x, window_y); - config_set_string(cat, "window_coordinates", temp); } else { config_delete_var(cat, "window_remember"); - config_delete_var(cat, "window_coordinates"); } if (vid_resize & 2) { @@ -2480,6 +2515,16 @@ save_video(void) else config_set_int(cat, "xga", xga_enabled); + if (gfxcard_2 == 0) + config_delete_var(cat, "gfxcard_2"); + else + config_set_string(cat, "gfxcard_2", video_get_internal_name(gfxcard_2)); + + if (show_second_monitors == 1) + config_delete_var(cat, "show_second_monitors"); + else + config_set_int(cat, "show_second_monitors", show_second_monitors); + delete_section_if_empty(cat); } @@ -3079,7 +3124,11 @@ save_other_removable_devices(void) void config_save(void) { + int i; + save_general(); /* General */ + for (i = 0; i < MONITORS_NUM; i++) + save_monitor(i); save_machine(); /* Machine */ save_video(); /* Video */ save_input_devices(); /* Input devices */ diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index c4ddaed4b..6afa66695 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -80,9 +80,11 @@ extern char log_path[1024]; /* (O) full path of logfile */ extern char vm_name[1024]; /* (O) display name of the VM */ -extern int window_w, window_h, /* (C) window size and */ - window_x, window_y, /* position info */ - window_remember, +#define window_x monitor_settings[0].mon_window_x +#define window_y monitor_settings[0].mon_window_y +#define window_w monitor_settings[0].mon_window_w +#define window_h monitor_settings[0].mon_window_h +extern int window_remember, vid_resize, /* (C) allow resizing */ invert_display, /* (C) invert the display */ suppress_overscan; /* (C) suppress overscans */ @@ -141,9 +143,6 @@ extern char cfg_path[1024]; /* full path of config file */ #ifndef USE_NEW_DYNAREC extern FILE *stdlog; /* file to log output to */ #endif -extern int scrnsz_x, /* current screen size, X */ - scrnsz_y; /* current screen size, Y */ -extern int efscrnsz_y; extern int config_changed; /* config has changed */ @@ -156,7 +155,9 @@ extern void pclog_toggle_suppr(void); extern void pclog(const char *fmt, ...); extern void fatal(const char *fmt, ...); extern void set_screen_size(int x, int y); +extern void set_screen_size_monitor(int x, int y, int monitor_index); extern void reset_screen_size(void); +extern void reset_screen_size_monitor(int monitor_index); extern void set_screen_size_natural(void); extern void update_mouse_msg(); #if 0 diff --git a/src/include/86box/plat.h b/src/include/86box/plat.h index 1f787da9e..5b810ed22 100644 --- a/src/include/86box/plat.h +++ b/src/include/86box/plat.h @@ -77,7 +77,6 @@ extern "C" { /* Global variables residing in the platform module. */ extern int dopause, /* system is paused */ mouse_capture; /* mouse is captured in app */ -extern atomic_flag_t doresize; /* screen resize requested */ extern volatile int is_quit; /* system exit requested */ #ifdef MTR_ENABLED @@ -90,9 +89,6 @@ extern char emu_version[200]; /* version ID string */ extern int rctrl_is_lalt; extern int update_icons; -extern int unscaled_size_x, /* current unscaled size X */ - unscaled_size_y; /* current unscaled size Y */ - extern int kbd_req_capture, hide_status_bar, hide_tool_bar; /* System-related functions. */ @@ -120,7 +116,8 @@ extern char *plat_vidapi_name(int api); extern int plat_setvid(int api); extern void plat_vidsize(int x, int y); extern void plat_setfullscreen(int on); -extern void plat_resize(int x, int y); +extern void plat_resize_monitor(int x, int y, int monitor_index); +extern void plat_resize(int x, int y); extern void plat_vidapi_enable(int enabled); extern void plat_vidapi_reload(void); extern void plat_vid_reload_options(void); diff --git a/src/include/86box/ui.h b/src/include/86box/ui.h index 6d3946d1c..847b8c706 100644 --- a/src/include/86box/ui.h +++ b/src/include/86box/ui.h @@ -62,6 +62,8 @@ extern void ui_check_menu_item(int id, int checked); extern wchar_t *ui_window_title(wchar_t *s); extern void ui_status_update(void); +extern void ui_init_monitor(int monitor_index); +extern void ui_deinit_monitor(int monitor_index); extern int ui_sb_find_part(int tag); extern void ui_sb_set_ready(int ready); extern void ui_sb_update_panes(void); diff --git a/src/include/86box/vid_cga.h b/src/include/86box/vid_cga.h index 26fe2ea1a..d36872e18 100644 --- a/src/include/86box/vid_cga.h +++ b/src/include/86box/vid_cga.h @@ -46,6 +46,8 @@ typedef struct cga_t int drawcursor; + int fullchange; + uint8_t *vram; uint8_t charbuffer[256]; diff --git a/src/include/86box/vid_ega.h b/src/include/86box/vid_ega.h index b007ac46d..f1ba7e417 100644 --- a/src/include/86box/vid_ega.h +++ b/src/include/86box/vid_ega.h @@ -46,14 +46,14 @@ typedef struct ega_t { readmode, writemode, readplane, vrammask, chain4, chain2_read, chain2_write, con, oddeven_page, oddeven_chain, vc, sc, - dispon, hdisp_on, cursoron, blink, + dispon, hdisp_on, cursoron, blink, fullchange, linepos, vslines, linecountff, oddeven, lowres, interlace, linedbl, lindebl, rowcount, vtotal, dispend, vsyncstart, split, hdisp, hdisp_old, htotal, hdisp_time, rowoffset, vblankstart, scrollcache, firstline, lastline, firstline_draw, lastline_draw, x_add, y_add, - displine, video_res_x, video_res_y, video_bpp, index; + displine, res_x, res_y, bpp, index; uint32_t charseta, charsetb, ma_latch, ma, maback, ca, vram_limit, overscan_color; diff --git a/src/include/86box/vid_hercules.h b/src/include/86box/vid_hercules.h index f97a8fa18..93785d9be 100644 --- a/src/include/86box/vid_hercules.h +++ b/src/include/86box/vid_hercules.h @@ -51,12 +51,18 @@ typedef struct { int vadj; int lp_ff; + int fullchange; int cols[256][2][2]; uint8_t *vram; + int monitor_index; + int prev_monitor_index; } hercules_t; +#define VIDEO_MONITOR_PROLOGUE() { dev->prev_monitor_index = monitor_index_global; monitor_index_global = dev->monitor_index; } +#define VIDEO_MONITOR_EPILOGUE() { monitor_index_global = dev->prev_monitor_index; } + static void *hercules_init(const device_t *info); #endif /*VIDEO_HERCULES_H*/ diff --git a/src/include/86box/vid_mda.h b/src/include/86box/vid_mda.h index 13e2f76e3..3e32ef848 100644 --- a/src/include/86box/vid_mda.h +++ b/src/include/86box/vid_mda.h @@ -25,11 +25,16 @@ typedef struct mda_t int con, coff, cursoron; int dispon, blink; int vsynctime; - int vadj; + int vadj; + int monitor_index; + int prev_monitor_index; uint8_t *vram; } mda_t; +#define VIDEO_MONITOR_PROLOGUE() { mda->prev_monitor_index = monitor_index_global; monitor_index_global = mda->monitor_index; } +#define VIDEO_MONITOR_EPILOGUE() { monitor_index_global = mda->prev_monitor_index; } + void mda_init(mda_t *mda); void mda_setcol(int chr, int blink, int fg, uint8_t cga_ink); void mda_out(uint16_t addr, uint8_t val, void *p); diff --git a/src/include/86box/vid_svga.h b/src/include/86box/vid_svga.h index 40613fe99..530ea648d 100644 --- a/src/include/86box/vid_svga.h +++ b/src/include/86box/vid_svga.h @@ -35,7 +35,7 @@ typedef struct { int ena, - x, y, xoff, yoff, xsize, ysize, + x, y, xoff, yoff, cur_xsize, cur_ysize, v_acc, h_acc; uint32_t addr, pitch; } hwcursor_t; diff --git a/src/include/86box/vid_xga.h b/src/include/86box/vid_xga.h index 4d70c601a..5890b5cad 100644 --- a/src/include/86box/vid_xga.h +++ b/src/include/86box/vid_xga.h @@ -22,7 +22,7 @@ typedef struct { int ena; - int x, y, xoff, yoff, xsize, ysize; + int x, y, xoff, yoff, cur_xsize, cur_ysize; uint32_t addr; } xga_hwcursor_t; diff --git a/src/include/86box/video.h b/src/include/86box/video.h index 513cb99ad..2847a7cb4 100644 --- a/src/include/86box/video.h +++ b/src/include/86box/video.h @@ -22,6 +22,12 @@ #ifndef EMU_VIDEO_H # define EMU_VIDEO_H +#ifdef __cplusplus +#include +using atomic_bool = std::atomic_bool; +#else +#include +#endif #define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) #define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) @@ -79,20 +85,93 @@ typedef struct { uint8_t chr[32]; } dbcs_font_t; +struct blit_data_struct; + +typedef struct monitor_t +{ + char name[512]; + int mon_xsize; + int mon_ysize; + int mon_scrnsz_x; + int mon_scrnsz_y; + int mon_efscrnsz_y; + int mon_unscaled_size_x; + int mon_unscaled_size_y; + int mon_res_x; + int mon_res_y; + int mon_bpp; + bitmap_t* target_buffer; + int mon_video_timing_read_b, + mon_video_timing_read_w, + mon_video_timing_read_l; + int mon_video_timing_write_b, + mon_video_timing_write_w, + mon_video_timing_write_l; + int mon_overscan_x; + int mon_overscan_y; + int mon_force_resize; + int mon_fullchange; + int mon_changeframecount; + int mon_screenshots; + uint32_t* mon_pal_lookup; + int* mon_cga_palette; + int mon_pal_lookup_static; /* Whether it should not be freed by the API. */ + int mon_cga_palette_static; /* Whether it should not be freed by the API. */ + const video_timings_t* mon_vid_timings; + int mon_vid_type; + struct blit_data_struct* mon_blit_data_ptr; +} monitor_t; + +typedef struct monitor_settings_t { + int mon_window_x; /* (C) window size and position info. */ + int mon_window_y; + int mon_window_w; + int mon_window_h; +} monitor_settings_t; + +#define MONITORS_NUM 8 +extern monitor_t monitors[MONITORS_NUM]; +extern monitor_settings_t monitor_settings[MONITORS_NUM]; +extern atomic_bool doresize_monitors[MONITORS_NUM]; +extern int monitor_index_global; +extern int gfxcard_2; +extern int show_second_monitors; + typedef rgb_t PALETTE[256]; -extern int changeframecount; +//extern int changeframecount; extern volatile int screenshots; -extern bitmap_t *buffer32; +//extern bitmap_t *buffer32; +#define buffer32 (monitors[monitor_index_global].target_buffer) +#define pal_lookup (monitors[monitor_index_global].mon_pal_lookup) +#define overscan_x (monitors[monitor_index_global].mon_overscan_x) +#define overscan_y (monitors[monitor_index_global].mon_overscan_y) +#define video_timing_read_b (monitors[monitor_index_global].mon_video_timing_read_b) +#define video_timing_read_l (monitors[monitor_index_global].mon_video_timing_read_l) +#define video_timing_read_w (monitors[monitor_index_global].mon_video_timing_read_w) +#define video_timing_write_b (monitors[monitor_index_global].mon_video_timing_write_b) +#define video_timing_write_l (monitors[monitor_index_global].mon_video_timing_write_l) +#define video_timing_write_w (monitors[monitor_index_global].mon_video_timing_write_w) +#define video_res_x (monitors[monitor_index_global].mon_res_x) +#define video_res_y (monitors[monitor_index_global].mon_res_y) +#define video_bpp (monitors[monitor_index_global].mon_bpp) +#define xsize (monitors[monitor_index_global].mon_xsize) +#define ysize (monitors[monitor_index_global].mon_ysize) +#define cga_palette (*monitors[monitor_index_global].mon_cga_palette) +#define changeframecount (monitors[monitor_index_global].mon_changeframecount) +#define scrnsz_x (monitors[monitor_index_global].mon_scrnsz_x) +#define scrnsz_y (monitors[monitor_index_global].mon_scrnsz_y) +#define efscrnsz_y (monitors[monitor_index_global].mon_efscrnsz_y) +#define unscaled_size_x (monitors[monitor_index_global].mon_unscaled_size_x) +#define unscaled_size_y (monitors[monitor_index_global].mon_unscaled_size_y) extern PALETTE cgapal, cgapal_mono[6]; -extern uint32_t pal_lookup[256]; +//extern uint32_t pal_lookup[256]; extern int video_fullscreen, video_fullscreen_scale, - video_fullscreen_first; -extern int fullchange; + video_fullscreen_first; extern uint8_t fontdat[2048][8]; extern uint8_t fontdatm[2048][16]; extern uint8_t fontdatw[512][32]; @@ -104,24 +183,11 @@ extern uint32_t *video_6to8, *video_8togs, *video_8to32, *video_15to32, - *video_16to32; -extern int xsize,ysize; + *video_16to32; extern int enable_overscan; -extern int overscan_x, - overscan_y; extern int force_43; -extern int video_timing_read_b, - video_timing_read_w, - video_timing_read_l; -extern int video_timing_write_b, - video_timing_write_w, - video_timing_write_l; -extern int video_res_x, - video_res_y, - video_bpp; extern int vid_resize; -extern int cga_palette, - herc_blend; +extern int herc_blend; extern int vid_cga_contrast; extern int video_grayscale; extern int video_graytype; @@ -134,6 +200,7 @@ extern int readflash; /* Function handler pointers. */ extern void (*video_recalctimings)(void); +extern void video_screenshot_monitor(uint32_t *buf, int start_x, int start_y, int row_len, int monitor_index); extern void video_screenshot(uint32_t *buf, int start_x, int start_y, int row_len); #ifdef _WIN32 @@ -153,34 +220,48 @@ extern const device_t *video_card_getdevice(int card); extern int video_card_has_config(int card); extern char *video_get_internal_name(int card); extern int video_get_video_from_internal_name(char *s); +extern int video_card_get_flags(int card); extern int video_is_mda(void); extern int video_is_cga(void); extern int video_is_ega_vga(void); extern void video_inform(int type, const video_timings_t *ptr); +extern void video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index); extern int video_get_type(void); +extern int video_get_type_monitor(int monitor_index); -extern void video_setblit(void(*blit)(int,int,int,int)); +extern void video_setblit(void(*blit)(int,int,int,int,int)); extern void video_blend(int x, int y); +extern void video_blend_monitor(int x, int y, int monitor_index); extern void video_blit_memtoscreen_8(int x, int y, int w, int h); +extern void video_blit_memtoscreen_8_monitor(int x, int y, int w, int h, int monitor_index); extern void video_blit_memtoscreen(int x, int y, int w, int h); +extern void video_blit_memtoscreen_monitor(int x, int y, int w, int h, int monitor_index); extern void video_blit_complete(void); extern void video_wait_for_blit(void); extern void video_wait_for_buffer(void); +extern void video_blit_complete_monitor(int monitor_index); +extern void video_wait_for_blit_monitor(int monitor_index); +extern void video_wait_for_buffer_monitor(int monitor_index); extern bitmap_t *create_bitmap(int w, int h); extern void destroy_bitmap(bitmap_t *b); +extern void cgapal_rebuild_monitor(int monitor_index); extern void cgapal_rebuild(void); extern void hline(bitmap_t *b, int x1, int y, int x2, uint32_t col); extern void updatewindowsize(int x, int y); +extern void video_monitor_init(int); +extern void video_monitor_close(int); extern void video_init(void); extern void video_close(void); extern void video_reset_close(void); extern void video_pre_reset(int card); extern void video_reset(int card); extern uint8_t video_force_resize_get(void); +extern uint8_t video_force_resize_get_monitor(int monitor_index); extern void video_force_resize_set(uint8_t res); +extern void video_force_resize_set_monitor(uint8_t res, int monitor_index); extern void video_update_timing(void); extern void loadfont_ex(char *s, int format, int offset); diff --git a/src/machine/m_amstrad.c b/src/machine/m_amstrad.c index e05d0d23e..27244189d 100644 --- a/src/machine/m_amstrad.c +++ b/src/machine/m_amstrad.c @@ -119,6 +119,7 @@ typedef struct { cursoron, cgablink; int vsynctime; + int fullchange; int vadj; uint16_t ma, maback; int dispon; @@ -242,7 +243,7 @@ vid_out_1512(uint16_t addr, uint8_t val, void *priv) vid->crtc[vid->crtcreg] = val & crtc_mask[vid->crtcreg]; if (old != val) { if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { - fullchange = changeframecount; + vid->fullchange = changeframecount; recalc_timings_1512(vid); } } @@ -1113,7 +1114,7 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) mda->crtc[mda->crtcreg] = val & crtc_mask[mda->crtcreg]; if (old != val) { if (mda->crtcreg < 0xe || mda->crtcreg > 0x10) { - fullchange = changeframecount; + vid->fullchange = changeframecount; mda_recalctimings(mda); } } @@ -1145,7 +1146,7 @@ vid_out_200(uint16_t addr, uint8_t val, void *priv) cga->crtc[cga->crtcreg] = val & crtc_mask[cga->crtcreg]; if (old != val) { if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) { - fullchange = changeframecount; + vid->fullchange = changeframecount; cga_recalctimings(cga); } } diff --git a/src/machine/m_at_compaq.c b/src/machine/m_at_compaq.c index 4f7181616..c67ccbb39 100644 --- a/src/machine/m_at_compaq.c +++ b/src/machine/m_at_compaq.c @@ -97,7 +97,7 @@ typedef struct compaq_plasma_t int linepos, displine; uint8_t *vram; uint64_t dispontime, dispofftime; - int dispon; + int dispon, fullchange; } compaq_plasma_t; static uint8_t cga_crtcmask[32] = @@ -375,7 +375,7 @@ compaq_plasma_out(uint16_t addr, uint8_t val, void *priv) if (old != val) { if (self->cga.crtcreg < 0xe || self->cga.crtcreg > 0x10) { - fullchange = changeframecount; + self->fullchange = changeframecount; compaq_plasma_recalctimings(self); } } diff --git a/src/machine/m_pcjr.c b/src/machine/m_pcjr.c index 4836da1bc..0a8b9cf46 100644 --- a/src/machine/m_pcjr.c +++ b/src/machine/m_pcjr.c @@ -81,6 +81,7 @@ typedef struct { int dispon; int con, coff, cursoron, blink; int vsynctime; + int fullchange; int vadj; uint16_t ma, maback; uint64_t dispontime, dispofftime; @@ -162,7 +163,7 @@ vid_out(uint16_t addr, uint8_t val, void *p) pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; if (old != val) { if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) { - fullchange = changeframecount; + pcjr->fullchange = changeframecount; recalc_timings(pcjr); } } diff --git a/src/machine/m_tandy.c b/src/machine/m_tandy.c index 39e5fe844..924466e8d 100644 --- a/src/machine/m_tandy.c +++ b/src/machine/m_tandy.c @@ -91,6 +91,7 @@ typedef struct { int con, coff, cursoron, blink; + int fullchange; int vsynctime; int vadj; uint16_t ma, maback; @@ -536,7 +537,7 @@ vid_out(uint16_t addr, uint8_t val, void *priv) vid->crtc[vid->crtcreg] = val & crtcmask[vid->crtcreg]; if (old != val) { if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { - fullchange = changeframecount; + vid->fullchange = changeframecount; recalc_timings(dev); } } diff --git a/src/qt/qt_d3d9renderer.cpp b/src/qt/qt_d3d9renderer.cpp index ae322de8d..3a8001be4 100644 --- a/src/qt/qt_d3d9renderer.cpp +++ b/src/qt/qt_d3d9renderer.cpp @@ -8,7 +8,7 @@ extern "C" #include <86box/video.h> } -D3D9Renderer::D3D9Renderer(QWidget *parent) +D3D9Renderer::D3D9Renderer(QWidget *parent, int monitor_index) : QWidget{parent}, RendererCommon() { QPalette pal = palette(); @@ -27,6 +27,7 @@ D3D9Renderer::D3D9Renderer(QWidget *parent) RendererCommon::parentWidget = parent; this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + this->m_monitor_index = monitor_index; } D3D9Renderer::~D3D9Renderer() @@ -138,8 +139,8 @@ void D3D9Renderer::resizeEvent(QResizeEvent *event) void D3D9Renderer::blit(int x, int y, int w, int h) { - if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || surfaceInUse) { - video_blit_complete(); + if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (monitors[m_monitor_index].target_buffer == NULL) || surfaceInUse) { + video_blit_complete_monitor(m_monitor_index); return; } surfaceInUse = true; @@ -152,16 +153,16 @@ void D3D9Renderer::blit(int x, int y, int w, int h) srcRect.right = source.right(); if (screenshots) { - video_screenshot((uint32_t *) &(buffer32->line[y][x]), 0, 0, 2048); + video_screenshot_monitor((uint32_t *) &(monitors[m_monitor_index].target_buffer->line[y][x]), 0, 0, 2048, m_monitor_index); } if (SUCCEEDED(d3d9surface->LockRect(&lockRect, &srcRect, 0))) { for (int y1 = 0; y1 < h; y1++) { - video_copy(((uint8_t*)lockRect.pBits) + (y1 * lockRect.Pitch), &(buffer32->line[y + y1][x]), w * 4); + video_copy(((uint8_t*)lockRect.pBits) + (y1 * lockRect.Pitch), &(monitors[m_monitor_index].target_buffer->line[y + y1][x]), w * 4); } - video_blit_complete(); + video_blit_complete_monitor(m_monitor_index); d3d9surface->UnlockRect(); } - else video_blit_complete(); + else video_blit_complete_monitor(m_monitor_index); surfaceInUse = false; QTimer::singleShot(0, this, [this] { this->update(); }); } diff --git a/src/qt/qt_d3d9renderer.hpp b/src/qt/qt_d3d9renderer.hpp index 21ef0ac59..d93781236 100644 --- a/src/qt/qt_d3d9renderer.hpp +++ b/src/qt/qt_d3d9renderer.hpp @@ -12,7 +12,7 @@ class D3D9Renderer : public QWidget, public RendererCommon { Q_OBJECT public: - explicit D3D9Renderer(QWidget *parent = nullptr); + explicit D3D9Renderer(QWidget *parent = nullptr, int monitor_index = 0); ~D3D9Renderer(); bool hasBlitFunc() override { return true; } void blit(int x, int y, int w, int h) override; @@ -39,6 +39,7 @@ private: std::atomic surfaceInUse{false}, finalized{false}; bool alreadyInitialized = false; + int m_monitor_index = 0; }; #endif // D3D9RENDERER_HPP diff --git a/src/qt/qt_hardwarerenderer.cpp b/src/qt/qt_hardwarerenderer.cpp index f285b5745..30ca74ecd 100644 --- a/src/qt/qt_hardwarerenderer.cpp +++ b/src/qt/qt_hardwarerenderer.cpp @@ -32,6 +32,7 @@ extern "C" { void HardwareRenderer::resizeGL(int w, int h) { + m_context->makeCurrent(this); glViewport(0, 0, qRound(w * devicePixelRatio()), qRound(h * devicePixelRatio())); } diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 30e3df2ee..f8469927e 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -122,19 +122,13 @@ main_thread_fn() /* Just so we dont overload the host OS. */ std::this_thread::sleep_for(std::chrono::milliseconds(1)); } - - /* If needed, handle a screen resize. */ - if (!atomic_flag_test_and_set(&doresize) && !video_fullscreen && !is_quit) { - if (vid_resize & 2) - plat_resize(fixed_size_x, fixed_size_y); - else - plat_resize(scrnsz_x, scrnsz_y); - } } is_quit = 1; } +static std::thread* main_thread; + int main(int argc, char* argv[]) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QApplication::setAttribute(Qt::AA_DisableHighDpiScaling, false); @@ -258,7 +252,7 @@ int main(int argc, char* argv[]) { main_window->installEventFilter(&socket); socket.connectToServer(qgetenv("86BOX_MANAGER_SOCKET")); } - pc_reset_hard_init(); + //pc_reset_hard_init(); /* Set the PAUSE mode depending on the renderer. */ // plat_pause(0); @@ -284,13 +278,38 @@ int main(int argc, char* argv[]) { } /* Initialize the rendering window, or fullscreen. */ - auto main_thread = std::thread([] { - main_thread_fn(); + QTimer::singleShot(0, &app, [] + { + pc_reset_hard_init(); + main_thread = new std::thread(main_thread_fn); }); + QTimer resizeTimer; + resizeTimer.setInterval(0); + resizeTimer.callOnTimeout([]() + { + /* If needed, handle a screen resize. */ + for (int i = 0; i < MONITORS_NUM; i++) { + if (!monitors[i].target_buffer) continue; + if (atomic_load(&doresize_monitors[i]) == 1 && !video_fullscreen && !is_quit) { + if (vid_resize & 2) + plat_resize_monitor(fixed_size_x, fixed_size_y, i); + else + plat_resize_monitor(monitors[i].mon_scrnsz_x, monitors[i].mon_scrnsz_y, i); + atomic_store(&doresize_monitors[i], 0); + } + } + + if (is_quit) { + QApplication::quit(); + } + }); + resizeTimer.start(); + auto ret = app.exec(); cpu_thread_run = 0; - main_thread.join(); + main_thread->join(); + pc_close(nullptr); socket.close(); return ret; diff --git a/src/qt/qt_mainwindow.cpp b/src/qt/qt_mainwindow.cpp index 14a4ff0bc..c2f1a52cf 100644 --- a/src/qt/qt_mainwindow.cpp +++ b/src/qt/qt_mainwindow.cpp @@ -20,6 +20,8 @@ * Copyright 2021-2022 Teemu Korhonen * Copyright 2022 dob205 */ +#include + #include "qt_mainwindow.hpp" #include "ui_qt_mainwindow.h" @@ -61,6 +63,7 @@ extern "C" { #include #include #include +#include #include #include #include @@ -120,7 +123,7 @@ static BMessageFilter* filter; #endif extern void qt_mouse_capture(int); -extern "C" void qt_blit(int x, int y, int w, int h); +extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index); MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), @@ -140,7 +143,7 @@ MainWindow::MainWindow(QWidget *parent) : statusBar()->setVisible(!hide_status_bar); statusBar()->setStyleSheet("QStatusBar::item {border: None; } QStatusBar QLabel { margin-right: 2px; margin-bottom: 1px; }"); ui->toolBar->setVisible(!hide_tool_bar); - + renderers[0].reset(nullptr); auto toolbar_spacer = new QWidget(); toolbar_spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); ui->toolBar->addWidget(toolbar_spacer); @@ -225,7 +228,7 @@ MainWindow::MainWindow(QWidget *parent) : }); connect(this, &MainWindow::resizeContents, this, [this](int w, int h) { - if (!QApplication::platformName().contains("eglfs") && vid_resize == 0) { + if (!QApplication::platformName().contains("eglfs") && vid_resize != 1) { w = (w / (!dpi_scale ? util::screenOfWidget(this)->devicePixelRatio() : 1.)); int modifiedHeight = (h / (!dpi_scale ? util::screenOfWidget(this)->devicePixelRatio() : 1.)) @@ -238,6 +241,18 @@ MainWindow::MainWindow(QWidget *parent) : } }); + connect(this, &MainWindow::resizeContentsMonitor, this, [this](int w, int h, int monitor_index) + { + if (!QApplication::platformName().contains("eglfs") && vid_resize != 1) { + qDebug() << "Resize"; + w = (w / (!dpi_scale ? util::screenOfWidget(renderers[monitor_index].get())->devicePixelRatio() : 1.)); + + int modifiedHeight = (h / (!dpi_scale ? util::screenOfWidget(renderers[monitor_index].get())->devicePixelRatio() : 1.)); + + renderers[monitor_index]->setFixedSize(w, modifiedHeight); + } + }); + connect(ui->menubar, &QMenuBar::triggered, this, [this] { config_save(); if (QApplication::activeWindow() == this) @@ -263,6 +278,7 @@ MainWindow::MainWindow(QWidget *parent) : ui->actionHiDPI_scaling->setChecked(dpi_scale); ui->actionHide_status_bar->setChecked(hide_status_bar); ui->actionHide_tool_bar->setChecked(hide_tool_bar); + ui->actionShow_non_primary_monitors->setChecked(show_second_monitors); ui->actionUpdate_status_bar_icons->setChecked(update_icons); ui->actionEnable_Discord_integration->setChecked(enable_discord); @@ -305,27 +321,33 @@ MainWindow::MainWindow(QWidget *parent) : connect(actGroup, &QActionGroup::triggered, [this](QAction* action) { vid_api = action->property("vid_api").toInt(); + RendererStack::Renderer newVidApi = RendererStack::Renderer::Software; switch (vid_api) { case 0: - ui->stackedWidget->switchRenderer(RendererStack::Renderer::Software); + newVidApi = RendererStack::Renderer::Software; break; case 1: - ui->stackedWidget->switchRenderer(RendererStack::Renderer::OpenGL); + newVidApi = (RendererStack::Renderer::OpenGL); break; case 2: - ui->stackedWidget->switchRenderer(RendererStack::Renderer::OpenGLES); + newVidApi = (RendererStack::Renderer::OpenGLES); break; case 3: - ui->stackedWidget->switchRenderer(RendererStack::Renderer::OpenGL3); + newVidApi = (RendererStack::Renderer::OpenGL3); break; case 4: - ui->stackedWidget->switchRenderer(RendererStack::Renderer::Vulkan); + newVidApi = (RendererStack::Renderer::Vulkan); break; case 5: - ui->stackedWidget->switchRenderer(RendererStack::Renderer::Direct3D9); + newVidApi = (RendererStack::Renderer::Direct3D9); break; } + ui->stackedWidget->switchRenderer(newVidApi); + if (!show_second_monitors) return; + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i]) renderers[i]->switchRenderer(newVidApi); + } }); connect(ui->stackedWidget, &RendererStack::rendererChanged, [this]() { @@ -495,6 +517,11 @@ MainWindow::MainWindow(QWidget *parent) : #endif setContextMenuPolicy(Qt::PreventContextMenu); + + connect(this, &MainWindow::initRendererMonitor, this, &MainWindow::initRendererMonitorSlot); + connect(this, &MainWindow::initRendererMonitorForNonQtThread, this, &MainWindow::initRendererMonitorSlot, Qt::BlockingQueuedConnection); + connect(this, &MainWindow::destroyRendererMonitor, this, &MainWindow::destroyRendererMonitorSlot); + connect(this, &MainWindow::destroyRendererMonitorForNonQtThread, this, &MainWindow::destroyRendererMonitorSlot, Qt::BlockingQueuedConnection); } void MainWindow::closeEvent(QCloseEvent *event) { @@ -527,18 +554,74 @@ void MainWindow::closeEvent(QCloseEvent *event) { window_x = this->geometry().x(); window_y = this->geometry().y(); } + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i]) { + monitor_settings[i].mon_window_w = renderers[i]->geometry().width(); + monitor_settings[i].mon_window_h = renderers[i]->geometry().height(); + if (!QApplication::platformName().contains("wayland")) continue; + monitor_settings[i].mon_window_x = renderers[i]->geometry().x(); + monitor_settings[i].mon_window_y = renderers[i]->geometry().y(); + } + } } - qt_nvr_save(); - config_save(); if (ui->stackedWidget->mouse_exit_func) ui->stackedWidget->mouse_exit_func(); ui->stackedWidget->switchRenderer(RendererStack::Renderer::Software); + + qt_nvr_save(); + config_save(); QApplication::processEvents(); + cpu_thread_run = 0; event->accept(); } +void MainWindow::initRendererMonitorSlot(int monitor_index) +{ + auto& secondaryRenderer = this->renderers[monitor_index]; + secondaryRenderer.reset(new RendererStack(nullptr, monitor_index)); + if (secondaryRenderer) { + connect(this, &MainWindow::pollMouse, secondaryRenderer.get(), &RendererStack::mousePoll, Qt::DirectConnection); + connect(secondaryRenderer.get(), &RendererStack::rendererChanged, this, [this, monitor_index] + { + this->renderers[monitor_index]->show(); + }); + secondaryRenderer->setWindowFlags(Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint); + secondaryRenderer->setWindowTitle(QObject::tr("86Box Monitor #") + QString::number(monitor_index + 1)); + + if (vid_resize == 2) { + secondaryRenderer->setFixedSize(fixed_size_x, fixed_size_y); + } + secondaryRenderer->setWindowIcon(this->windowIcon()); + if (show_second_monitors) { + secondaryRenderer->show(); + if (window_remember) { + secondaryRenderer->setGeometry(monitor_settings[monitor_index].mon_window_x < 120 ? 120 : monitor_settings[monitor_index].mon_window_x, + monitor_settings[monitor_index].mon_window_y < 120 ? 120 : monitor_settings[monitor_index].mon_window_y, + monitor_settings[monitor_index].mon_window_w > 2048 ? 2048 : monitor_settings[monitor_index].mon_window_w, + monitor_settings[monitor_index].mon_window_h > 2048 ? 2048 : monitor_settings[monitor_index].mon_window_h); + } + secondaryRenderer->switchRenderer((RendererStack::Renderer)vid_api); + } + + } +} + +void MainWindow::destroyRendererMonitorSlot(int monitor_index) +{ + if (this->renderers[monitor_index]) { + if (window_remember) { + monitor_settings[monitor_index].mon_window_w = renderers[monitor_index]->geometry().width(); + monitor_settings[monitor_index].mon_window_h = renderers[monitor_index]->geometry().height(); + monitor_settings[monitor_index].mon_window_x = renderers[monitor_index]->geometry().x(); + monitor_settings[monitor_index].mon_window_y = renderers[monitor_index]->geometry().y(); + } + config_save(); + this->renderers[monitor_index].release()->deleteLater(); + } +} + MainWindow::~MainWindow() { delete ui; } @@ -546,6 +629,7 @@ MainWindow::~MainWindow() { void MainWindow::showEvent(QShowEvent *event) { if (shownonce) return; shownonce = true; + if (window_remember) resize(window_w, window_h + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()) + (hide_tool_bar ? 0 : ui->toolBar->height())); if (window_remember && !QApplication::platformName().contains("wayland")) { setGeometry(window_x, window_y, window_w, window_h + menuBar()->height() + (hide_status_bar ? 0 : statusBar()->height()) + (hide_tool_bar ? 0 : ui->toolBar->height())); } @@ -555,15 +639,8 @@ void MainWindow::showEvent(QShowEvent *event) { + (hide_status_bar ? 0 : statusBar()->height()) + (hide_tool_bar ? 0 : ui->toolBar->height())); - scrnsz_x = fixed_size_x; - scrnsz_y = fixed_size_y; - } - else if (window_remember && vid_resize == 1) { - ui->stackedWidget->setFixedSize(window_w, window_h); - adjustSize(); - ui->stackedWidget->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); - scrnsz_x = window_w; - scrnsz_y = window_h; + monitors[0].mon_scrnsz_x = fixed_size_x; + monitors[0].mon_scrnsz_y = fixed_size_y; } } @@ -1361,7 +1438,7 @@ void MainWindow::on_actionFullscreen_triggered() { + (!hide_status_bar ? statusBar()->height() : 0) + (!hide_tool_bar ? ui->toolBar->height() : 0)); - emit resizeContents(scrnsz_x, scrnsz_y); + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); } } else { if (video_fullscreen_first) @@ -1495,9 +1572,13 @@ void MainWindow::keyPressEvent(QKeyEvent* event) event->accept(); } -void MainWindow::blitToWidget(int x, int y, int w, int h) +void MainWindow::blitToWidget(int x, int y, int w, int h, int monitor_index) { - ui->stackedWidget->blit(x, y, w, h); + if (monitor_index >= 1) { + if (renderers[monitor_index]) renderers[monitor_index]->blit(x, y, w, h); + else video_blit_complete_monitor(monitor_index); + } + else ui->stackedWidget->blit(x, y, w, h); } void MainWindow::keyReleaseEvent(QKeyEvent* event) @@ -1536,16 +1617,34 @@ void MainWindow::on_actionResizable_window_triggered(bool checked) { setWindowFlag(Qt::WindowMaximizeButtonHint); setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, false); setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + for (int i = 1; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer) { + renderers[i]->setWindowFlag(Qt::WindowMaximizeButtonHint); + renderers[i]->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + } + } } else { vid_resize = 0; setWindowFlag(Qt::WindowMaximizeButtonHint, false); setWindowFlag(Qt::MSWindowsFixedSizeDialogHint); + for (int i = 1; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer) { + renderers[i]->setWindowFlag(Qt::WindowMaximizeButtonHint, false); + emit resizeContentsMonitor(monitors[i].mon_scrnsz_x, monitors[i].mon_scrnsz_y, i); + } + } } show(); - ui->stackedWidget->switchRenderer((RendererStack::Renderer)vid_api); - ui->menuWindow_scale_factor->setEnabled(! checked); - emit resizeContents(scrnsz_x, scrnsz_y); + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); + ui->stackedWidget->switchRenderer((RendererStack::Renderer)vid_api); + for (int i = 1; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer && show_second_monitors) { + renderers[i]->show(); + renderers[i]->switchRenderer((RendererStack::Renderer)vid_api); + QApplication::processEvents(); + } + } } static void @@ -1558,6 +1657,9 @@ video_toggle_option(QAction* action, int *val) endblit(); config_save(); device_force_redraw(); + for (int i = 0; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer) video_force_resize_set_monitor(1, i); + } } void MainWindow::on_actionInverted_VGA_monitor_triggered() { @@ -1572,8 +1674,9 @@ static void update_scaled_checkboxes(Ui::MainWindow* ui, QAction* selected) { reset_screen_size(); device_force_redraw(); - video_force_resize_set(1); - atomic_flag_clear(&doresize); + for (int i = 0; i < MONITORS_NUM; i++) { + if (monitors[i].target_buffer) video_force_resize_set_monitor(1, i); + } config_save(); } @@ -1752,7 +1855,6 @@ void MainWindow::on_actionChange_contrast_for_monochrome_display_triggered() { void MainWindow::on_actionForce_4_3_display_ratio_triggered() { video_toggle_option(ui->actionForce_4_3_display_ratio, &force_43); - video_force_resize_set(1); } void MainWindow::on_actionRemember_size_and_position_triggered() @@ -1764,6 +1866,14 @@ void MainWindow::on_actionRemember_size_and_position_triggered() window_x = geometry().x(); window_y = geometry().y(); } + for (int i = 1; i < MONITORS_NUM; i++) { + if (window_remember && renderers[i]) { + monitor_settings[i].mon_window_w = renderers[i]->geometry().width(); + monitor_settings[i].mon_window_h = renderers[i]->geometry().height(); + monitor_settings[i].mon_window_x = renderers[i]->geometry().x(); + monitor_settings[i].mon_window_y = renderers[i]->geometry().y(); + } + } ui->actionRemember_size_and_position->setChecked(window_remember); } @@ -1778,7 +1888,10 @@ void MainWindow::on_actionHiDPI_scaling_triggered() { dpi_scale ^= 1; ui->actionHiDPI_scaling->setChecked(dpi_scale); - emit resizeContents(scrnsz_x, scrnsz_y); + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i]) emit resizeContentsMonitor(monitors[i].mon_scrnsz_x, monitors[i].mon_scrnsz_y, i); + } } void MainWindow::on_actionHide_status_bar_triggered() @@ -1794,7 +1907,7 @@ void MainWindow::on_actionHide_status_bar_triggered() } else { int vid_resize_orig = vid_resize; vid_resize = 0; - emit resizeContents(scrnsz_x, scrnsz_y); + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); vid_resize = vid_resize_orig; } } @@ -1812,7 +1925,7 @@ void MainWindow::on_actionHide_tool_bar_triggered() } else { int vid_resize_orig = vid_resize; vid_resize = 0; - emit resizeContents(scrnsz_x, scrnsz_y); + emit resizeContents(monitors[0].mon_scrnsz_x, monitors[0].mon_scrnsz_y); vid_resize = vid_resize_orig; } } @@ -1826,7 +1939,8 @@ void MainWindow::on_actionUpdate_status_bar_icons_triggered() void MainWindow::on_actionTake_screenshot_triggered() { startblit(); - screenshots++; + for (int i = 0; i < MONITORS_NUM; i++) + monitors[i].mon_screenshots++; endblit(); device_force_redraw(); } @@ -1892,8 +2006,13 @@ void MainWindow::on_actionRenderer_options_triggered() { auto dlg = ui->stackedWidget->getOptions(this); - if (dlg) - dlg->exec(); + if (dlg) { + if (dlg->exec() == QDialog::Accepted) { + for (int i = 1; i < MONITORS_NUM; i++) { + if (renderers[i] && renderers[i]->hasOptions()) renderers[i]->reloadOptions(); + } + } + } } void MainWindow::on_actionMCA_devices_triggered() @@ -1904,3 +2023,36 @@ void MainWindow::on_actionMCA_devices_triggered() dlg->exec(); } + +void MainWindow::on_actionShow_non_primary_monitors_triggered() +{ + show_second_monitors ^= 1; + + if (show_second_monitors) { + for (int monitor_index = 1; monitor_index < MONITORS_NUM; monitor_index++) { + auto& secondaryRenderer = renderers[monitor_index]; + if (!renderers[monitor_index]) continue; + secondaryRenderer->show(); + if (window_remember) { + secondaryRenderer->setGeometry(monitor_settings[monitor_index].mon_window_x < 120 ? 120 : monitor_settings[monitor_index].mon_window_x, + monitor_settings[monitor_index].mon_window_y < 120 ? 120 : monitor_settings[monitor_index].mon_window_y, + monitor_settings[monitor_index].mon_window_w > 2048 ? 2048 : monitor_settings[monitor_index].mon_window_w, + monitor_settings[monitor_index].mon_window_h > 2048 ? 2048 : monitor_settings[monitor_index].mon_window_h); + } + secondaryRenderer->switchRenderer((RendererStack::Renderer)vid_api); + } + } else { + for (int monitor_index = 1; monitor_index < MONITORS_NUM; monitor_index++) { + auto& secondaryRenderer = renderers[monitor_index]; + if (!renderers[monitor_index]) continue; + secondaryRenderer->hide(); + if (window_remember && renderers[monitor_index]) { + monitor_settings[monitor_index].mon_window_w = renderers[monitor_index]->geometry().width(); + monitor_settings[monitor_index].mon_window_h = renderers[monitor_index]->geometry().height(); + monitor_settings[monitor_index].mon_window_x = renderers[monitor_index]->geometry().x(); + monitor_settings[monitor_index].mon_window_y = renderers[monitor_index]->geometry().y(); + } + } + } +} + diff --git a/src/qt/qt_mainwindow.hpp b/src/qt/qt_mainwindow.hpp index ff16e6e88..30163429a 100644 --- a/src/qt/qt_mainwindow.hpp +++ b/src/qt/qt_mainwindow.hpp @@ -9,6 +9,7 @@ #include class MediaMenu; +class RendererStack; namespace Ui { class MainWindow; @@ -26,12 +27,13 @@ public: void showMessage(int flags, const QString& header, const QString& message); void getTitle(wchar_t* title); - void blitToWidget(int x, int y, int w, int h); + void blitToWidget(int x, int y, int w, int h, int monitor_index); QSize getRenderWidgetSize(); void setSendKeyboardInput(bool enabled); signals: void paint(const QImage& image); void resizeContents(int w, int h); + void resizeContentsMonitor(int w, int h, int monitor_index); void pollMouse(); void statusBarMessage(const QString& msg); void updateStatusBarPanes(); @@ -40,6 +42,10 @@ signals: void updateStatusBarTip(int tag); void updateMenuResizeOptions(); void updateWindowRememberOption(); + void initRendererMonitor(int monitor_index); + void destroyRendererMonitor(int monitor_index); + void initRendererMonitorForNonQtThread(int monitor_index); + void destroyRendererMonitorForNonQtThread(int monitor_index); void setTitle(const QString& title); void setFullscreen(bool state); @@ -51,6 +57,8 @@ public slots: void showSettings(); void hardReset(); void togglePause(); + void initRendererMonitorSlot(int monitor_index); + void destroyRendererMonitorSlot(int monitor_index); private slots: void on_actionFullscreen_triggered(); void on_actionSettings_triggered(); @@ -115,9 +123,13 @@ protected: void closeEvent(QCloseEvent* event) override; void changeEvent(QEvent* event) override; +private slots: + void on_actionShow_non_primary_monitors_triggered(); + private: Ui::MainWindow *ui; std::unique_ptr status; + std::array, 8> renderers; std::shared_ptr mm; #ifdef Q_OS_MACOS diff --git a/src/qt/qt_mainwindow.ui b/src/qt/qt_mainwindow.ui index 6d48cb596..f077f7e97 100644 --- a/src/qt/qt_mainwindow.ui +++ b/src/qt/qt_mainwindow.ui @@ -54,7 +54,7 @@ 0 0 724 - 21 + 23 @@ -161,6 +161,7 @@ + @@ -757,6 +758,14 @@ 5 + + + true + + + Show non-primary monitors + + diff --git a/src/qt/qt_openglrenderer.cpp b/src/qt/qt_openglrenderer.cpp index d4724fdde..918ba155a 100644 --- a/src/qt/qt_openglrenderer.cpp +++ b/src/qt/qt_openglrenderer.cpp @@ -29,6 +29,7 @@ OpenGLRenderer::OpenGLRenderer(QWidget *parent) : QWindow(parent->windowHandle()) , renderTimer(new QTimer(this)) + , options(nullptr) { renderTimer->setTimerType(Qt::PreciseTimer); /* TODO: need's more accuracy, maybe target 1ms earlier and spin yield */ @@ -165,9 +166,7 @@ OpenGLRenderer::initialize() glTexImage2D(GL_TEXTURE_2D, 0, QOpenGLTexture::RGBA8_UNorm, INIT_WIDTH, INIT_HEIGHT, 0, QOpenGLTexture::BGRA, QOpenGLTexture::UInt32_RGBA8_Rev, NULL); - options = new OpenGLOptions(this, true, glslVersion); - - applyOptions(); + reloadOptions(); glClearColor(0.f, 0.f, 0.f, 1.f); @@ -304,6 +303,15 @@ OpenGLRenderer::applyOptions() currentFilter = options->filter(); } +void +OpenGLRenderer::reloadOptions() +{ + if (options) { delete options; options = nullptr; } + options = new OpenGLOptions(this, true, glslVersion); + + applyOptions(); +} + void OpenGLRenderer::applyShader(const OpenGLShaderPass &shader) { diff --git a/src/qt/qt_openglrenderer.hpp b/src/qt/qt_openglrenderer.hpp index a83eac5dc..a27e0fe21 100644 --- a/src/qt/qt_openglrenderer.hpp +++ b/src/qt/qt_openglrenderer.hpp @@ -53,6 +53,7 @@ public: void finalize() override final; bool hasOptions() const override { return true; } QDialog *getOptions(QWidget *parent) override; + void reloadOptions() override; signals: void initialized(); diff --git a/src/qt/qt_platform.cpp b/src/qt/qt_platform.cpp index 03a4871b1..3f323b12f 100644 --- a/src/qt/qt_platform.cpp +++ b/src/qt/qt_platform.cpp @@ -52,7 +52,7 @@ extern MainWindow* main_window; QElapsedTimer elapsed_timer; static std::atomic_int blitmx_contention = 0; -static std::mutex blitmx; +static std::recursive_mutex blitmx; class CharPointer { public: diff --git a/src/qt/qt_renderercommon.hpp b/src/qt/qt_renderercommon.hpp index 4d346a8e5..1a0bf73e1 100644 --- a/src/qt/qt_renderercommon.hpp +++ b/src/qt/qt_renderercommon.hpp @@ -28,6 +28,8 @@ public: virtual bool hasOptions() const { return false; } /* Returns options dialog for renderer */ virtual QDialog *getOptions(QWidget *parent) { return nullptr; } + /* Reloads options of renderer */ + virtual void reloadOptions() {} virtual bool hasBlitFunc() { return false; } virtual void blit(int x, int y, int w, int h) {} diff --git a/src/qt/qt_rendererstack.cpp b/src/qt/qt_rendererstack.cpp index c7f1984a7..ae451db6c 100644 --- a/src/qt/qt_rendererstack.cpp +++ b/src/qt/qt_rendererstack.cpp @@ -44,6 +44,7 @@ #endif extern "C" { +#include <86box/86box.h> #include <86box/mouse.h> #include <86box/plat.h> #include <86box/video.h> @@ -51,14 +52,21 @@ extern "C" { double mouse_sensitivity = 1.0; } +struct mouseinputdata { + int deltax, deltay, deltaz; + int mousebuttons; +}; +static mouseinputdata mousedata; + extern "C" void macos_poll_mouse(); extern MainWindow *main_window; -RendererStack::RendererStack(QWidget *parent) +RendererStack::RendererStack(QWidget *parent, int monitor_index) : QStackedWidget(parent) , ui(new Ui::RendererStack) { ui->setupUi(this); + m_monitor_index = monitor_index; #if defined __unix__ && !defined __HAIKU__ char *mouse_type = getenv("EMU86BOX_MOUSE"), auto_mouse_type[16]; if (!mouse_type || (mouse_type[0] == '\0') || !stricmp(mouse_type, "auto")) { @@ -313,7 +321,7 @@ RendererStack::createRenderer(Renderer renderer) case Renderer::Direct3D9: { this->createWinId(); - auto hw = new D3D9Renderer(this); + auto hw = new D3D9Renderer(this, m_monitor_index); rendererWindow = hw; connect(hw, &D3D9Renderer::error, this, [this](QString str) { @@ -398,14 +406,14 @@ RendererStack::createRenderer(Renderer renderer) void RendererStack::blitDummy(int x, int y, int w, int h) { - video_blit_complete(); + video_blit_complete_monitor(m_monitor_index); blitDummied = true; } void RendererStack::blitRenderer(int x, int y, int w, int h) { - if (blitDummied) { blitDummied = false; video_blit_complete(); return; } + if (blitDummied) { blitDummied = false; video_blit_complete_monitor(m_monitor_index); return; } directBlitting = true; rendererWindow->blit(x, y, w, h); directBlitting = false; @@ -415,8 +423,8 @@ RendererStack::blitRenderer(int x, int y, int w, int h) void RendererStack::blitCommon(int x, int y, int w, int h) { - if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || imagebufs.empty() || std::get(imagebufs[currentBuf])->test_and_set() || blitDummied) { - video_blit_complete(); + if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (monitors[m_monitor_index].target_buffer == NULL) || imagebufs.empty() || std::get(imagebufs[currentBuf])->test_and_set() || blitDummied) { + video_blit_complete_monitor(m_monitor_index); return; } sx = x; @@ -426,13 +434,21 @@ RendererStack::blitCommon(int x, int y, int w, int h) uint8_t *imagebits = std::get(imagebufs[currentBuf]); for (int y1 = y; y1 < (y + h); y1++) { auto scanline = imagebits + (y1 * rendererWindow->getBytesPerRow()) + (x * 4); - video_copy(scanline, &(buffer32->line[y1][x]), w * 4); + video_copy(scanline, &(monitors[m_monitor_index].target_buffer->line[y1][x]), w * 4); } - if (screenshots) { - video_screenshot((uint32_t *) imagebits, x, y, 2048); + if (monitors[m_monitor_index].mon_screenshots) { + video_screenshot_monitor((uint32_t *) imagebits, x, y, 2048, m_monitor_index); } - video_blit_complete(); + video_blit_complete_monitor(m_monitor_index); emit blitToRenderer(currentBuf, sx, sy, sw, sh); currentBuf = (currentBuf + 1) % imagebufs.size(); } + +void RendererStack::closeEvent(QCloseEvent* event) +{ + if (cpu_thread_run == 0 || is_quit == 1) { event->accept(); return; } + event->ignore(); + main_window->close(); +} + diff --git a/src/qt/qt_rendererstack.hpp b/src/qt/qt_rendererstack.hpp index ab8e160ec..72495ec33 100644 --- a/src/qt/qt_rendererstack.hpp +++ b/src/qt/qt_rendererstack.hpp @@ -23,7 +23,7 @@ class RendererStack : public QStackedWidget { Q_OBJECT public: - explicit RendererStack(QWidget *parent = nullptr); + explicit RendererStack(QWidget *parent = nullptr, int monitor_index = 0); ~RendererStack(); void mousePressEvent(QMouseEvent *event) override; @@ -31,6 +31,7 @@ public: void mouseMoveEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override; void leaveEvent(QEvent *event) override; + void closeEvent(QCloseEvent *event) override; void keyPressEvent(QKeyEvent *event) override { event->ignore(); @@ -52,6 +53,8 @@ public: /* Does current renderer implement options dialog */ bool hasOptions() const { return rendererWindow ? rendererWindow->hasOptions() : false; } + /* Reloads options of current renderer */ + void reloadOptions() const { return rendererWindow->reloadOptions(); } /* Returns options dialog for current renderer */ QDialog *getOptions(QWidget *parent) { return rendererWindow ? rendererWindow->getOptions(parent) : nullptr; } @@ -87,16 +90,11 @@ private: Ui::RendererStack *ui; - struct mouseinputdata { - int deltax, deltay, deltaz; - int mousebuttons; - }; - mouseinputdata mousedata; - int x, y, w, h, sx, sy, sw, sh; int currentBuf = 0; int isMouseDown = 0; + int m_monitor_index = 0; std::vector> imagebufs; diff --git a/src/qt/qt_settingsdisplay.cpp b/src/qt/qt_settingsdisplay.cpp index e3fac08ec..84054806d 100644 --- a/src/qt/qt_settingsdisplay.cpp +++ b/src/qt/qt_settingsdisplay.cpp @@ -46,6 +46,7 @@ SettingsDisplay::~SettingsDisplay() void SettingsDisplay::save() { gfxcard = ui->comboBoxVideo->currentData().toInt(); + gfxcard_2 = ui->comboBoxVideoSecondary->currentData().toInt(); voodoo_enabled = ui->checkBoxVoodoo->isChecked() ? 1 : 0; ibm8514_enabled = ui->checkBox8514->isChecked() ? 1 : 0; xga_enabled = ui->checkBoxXga->isChecked() ? 1 : 0; @@ -87,11 +88,16 @@ void SettingsDisplay::onCurrentMachineChanged(int machineId) { if (machine_has_flags(machineId, MACHINE_VIDEO_ONLY) > 0) { ui->comboBoxVideo->setEnabled(false); + ui->comboBoxVideoSecondary->setEnabled(false); + ui->pushButtonConfigureSecondary->setEnabled(false); selectedRow = 1; } else { ui->comboBoxVideo->setEnabled(true); + ui->comboBoxVideoSecondary->setEnabled(true); + ui->pushButtonConfigureSecondary->setEnabled(true); } ui->comboBoxVideo->setCurrentIndex(selectedRow); + if (gfxcard_2 == 0) ui->pushButtonConfigureSecondary->setEnabled(false); } void SettingsDisplay::on_pushButtonConfigure_clicked() { @@ -137,6 +143,41 @@ void SettingsDisplay::on_comboBoxVideo_currentIndexChanged(int index) { ui->checkBoxXga->setChecked(xga_enabled); ui->pushButtonConfigureXga->setEnabled((hasIsa16 || has_MCA) && ui->checkBoxXga->isChecked()); + + int c = 2; + + ui->comboBoxVideoSecondary->clear(); + ui->comboBoxVideoSecondary->addItem(QObject::tr("None"), 0); + + ui->comboBoxVideoSecondary->setCurrentIndex(0); + // TODO: Implement support for selecting non-MDA secondary cards properly when MDA cards are the primary ones. + if (video_card_get_flags(videoCard) == VIDEO_FLAG_TYPE_MDA) { + ui->comboBoxVideoSecondary->setCurrentIndex(0); + return; + } + while (true) { + const device_t* video_dev = video_card_getdevice(c); + QString name = DeviceConfig::DeviceName(video_dev, video_get_internal_name(c), 1); + if (name.isEmpty()) { + break; + } + + if (video_card_available(c) && + device_is_valid(video_dev, machineId) && + !(video_card_get_flags(c) == video_card_get_flags(videoCard))) { + ui->comboBoxVideoSecondary->addItem(name, c); + if (c == gfxcard_2) + ui->comboBoxVideoSecondary->setCurrentIndex(ui->comboBoxVideoSecondary->count() - 1); + } + + c++; + } + + if (gfxcard_2 == 0 || (machine_has_flags(machineId, MACHINE_VIDEO_ONLY) > 0)) + { + ui->comboBoxVideoSecondary->setCurrentIndex(0); + ui->pushButtonConfigureSecondary->setEnabled(false); + } } void SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) { @@ -146,3 +187,21 @@ void SettingsDisplay::on_checkBoxVoodoo_stateChanged(int state) { void SettingsDisplay::on_checkBoxXga_stateChanged(int state) { ui->pushButtonConfigureXga->setEnabled(state == Qt::Checked); } + +void SettingsDisplay::on_comboBoxVideoSecondary_currentIndexChanged(int index) +{ + if (index < 0) { + ui->pushButtonConfigureSecondary->setEnabled(false); + return; + } + int videoCard = ui->comboBoxVideoSecondary->currentData().toInt(); + ui->pushButtonConfigureSecondary->setEnabled(index != 0 && video_card_has_config(videoCard) > 0); +} + + +void SettingsDisplay::on_pushButtonConfigureSecondary_clicked() +{ + auto* device = video_card_getdevice(ui->comboBoxVideoSecondary->currentData().toInt()); + DeviceConfig::ConfigureDevice(device, 0, qobject_cast(Settings::settings)); +} + diff --git a/src/qt/qt_settingsdisplay.hpp b/src/qt/qt_settingsdisplay.hpp index 44e688d9a..06badd656 100644 --- a/src/qt/qt_settingsdisplay.hpp +++ b/src/qt/qt_settingsdisplay.hpp @@ -20,6 +20,12 @@ public: public slots: void onCurrentMachineChanged(int machineId); +private slots: + void on_pushButtonConfigureSecondary_clicked(); + +private slots: + void on_comboBoxVideoSecondary_currentIndexChanged(int index); + private slots: void on_checkBoxVoodoo_stateChanged(int state); void on_checkBoxXga_stateChanged(int state); diff --git a/src/qt/qt_settingsdisplay.ui b/src/qt/qt_settingsdisplay.ui index 58032a17b..c9bbaf1c7 100644 --- a/src/qt/qt_settingsdisplay.ui +++ b/src/qt/qt_settingsdisplay.ui @@ -26,16 +26,29 @@ 0 - - - - - + + - Video: + 8514/A + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + @@ -49,53 +62,57 @@ - - - - Configure - - - - + Voodoo Graphics - - - - 8514/A - - - - - + + Configure - + + + + Video: + + + + XGA - - - - Qt::Vertical + + + + Configure - - - 20 - 40 - + + + + + + Video #2: - + + + + + + + + + Configure + + diff --git a/src/qt/qt_specifydimensions.cpp b/src/qt/qt_specifydimensions.cpp index 9d8daac0f..1fc294d79 100644 --- a/src/qt/qt_specifydimensions.cpp +++ b/src/qt/qt_specifydimensions.cpp @@ -20,9 +20,12 @@ #include "qt_mainwindow.hpp" #include "ui_qt_mainwindow.h" +#include "qt_util.hpp" + #include #include #include +#include extern "C" { @@ -44,6 +47,11 @@ SpecifyDimensions::SpecifyDimensions(QWidget *parent) : ui->spinBoxWidth->setValue(main_window->getRenderWidgetSize().width()); ui->spinBoxHeight->setRange(16, 2048); ui->spinBoxHeight->setValue(main_window->getRenderWidgetSize().height()); + + if (dpi_scale == 0) { + ui->spinBoxWidth->setValue(main_window->getRenderWidgetSize().width() * util::screenOfWidget(main_window)->devicePixelRatio()); + ui->spinBoxHeight->setValue(main_window->getRenderWidgetSize().height() * util::screenOfWidget(main_window)->devicePixelRatio()); + } } SpecifyDimensions::~SpecifyDimensions() @@ -62,14 +70,21 @@ void SpecifyDimensions::on_SpecifyDimensions_accepted() fixed_size_x = ui->spinBoxWidth->value(); fixed_size_y = ui->spinBoxHeight->value(); - main_window->setFixedSize(ui->spinBoxWidth->value(), - ui->spinBoxHeight->value() - + (!hide_status_bar ? main_window->statusBar()->height() : 0) - + (!hide_tool_bar ? main_window->ui->toolBar->height() : 0) - + main_window->menuBar()->height()); + main_window->resizeContents(fixed_size_x, fixed_size_y); emit main_window->updateMenuResizeOptions(); main_window->show(); + for (int i = 1; i < MONITORS_NUM; i++) { + if (main_window->renderers[i]) { + main_window->renderers[i]->setWindowFlag(Qt::WindowMaximizeButtonHint, false); + main_window->renderers[i]->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint); + emit main_window->resizeContentsMonitor(fixed_size_x, fixed_size_y, i); + if (show_second_monitors) { + main_window->renderers[i]->show(); + main_window->renderers[i]->switchRenderer((RendererStack::Renderer)vid_api); + } + } + } main_window->ui->stackedWidget->switchRenderer((RendererStack::Renderer)vid_api); } else @@ -83,6 +98,16 @@ void SpecifyDimensions::on_SpecifyDimensions_accepted() window_h = ui->spinBoxHeight->value(); main_window->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); emit main_window->resizeContents(ui->spinBoxWidth->value(), ui->spinBoxHeight->value()); + for (int i = 1; i < MONITORS_NUM; i++) { + if (main_window->renderers[i]) { + main_window->renderers[i]->setWindowFlag(Qt::WindowMaximizeButtonHint); + main_window->renderers[i]->setWindowFlag(Qt::MSWindowsFixedSizeDialogHint, false); + emit main_window->resizeContentsMonitor(ui->spinBoxWidth->value(), ui->spinBoxHeight->value(), i); + main_window->renderers[i]->setFixedSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); + if (show_second_monitors) { main_window->renderers[i]->show(); + main_window->renderers[i]->switchRenderer((RendererStack::Renderer)vid_api); } + } + } vid_resize = 1; emit main_window->updateMenuResizeOptions(); } diff --git a/src/qt/qt_ui.cpp b/src/qt/qt_ui.cpp index 754e09e89..128631282 100644 --- a/src/qt/qt_ui.cpp +++ b/src/qt/qt_ui.cpp @@ -55,17 +55,18 @@ wchar_t* ui_window_title(wchar_t* str) return str; } -extern "C" void qt_blit(int x, int y, int w, int h) +extern "C" void qt_blit(int x, int y, int w, int h, int monitor_index) { - main_window->blitToWidget(x, y, w, h); + main_window->blitToWidget(x, y, w, h, monitor_index); } void mouse_poll() { main_window->pollMouse(); } -void plat_resize(int w, int h) { - main_window->resizeContents(w, h); +void plat_resize_monitor(int w, int h, int monitor_index) { + if (monitor_index >= 1) main_window->resizeContentsMonitor(w, h, monitor_index); + else main_window->resizeContents(w, h); } void plat_setfullscreen(int on) { @@ -98,6 +99,20 @@ int ui_msgbox_header(int flags, void *header, void* message) { return 0; } +void ui_init_monitor(int monitor_index) { + if (QThread::currentThread() == main_window->thread()) { + emit main_window->initRendererMonitor(monitor_index); + } + else emit main_window->initRendererMonitorForNonQtThread(monitor_index); +} + +void ui_deinit_monitor(int monitor_index) { + if (QThread::currentThread() == main_window->thread()) { + emit main_window->destroyRendererMonitor(monitor_index); + } + else emit main_window->destroyRendererMonitorForNonQtThread(monitor_index); +} + int ui_msgbox(int flags, void *message) { return ui_msgbox_header(flags, nullptr, message); } diff --git a/src/qt/wl_mouse.cpp b/src/qt/wl_mouse.cpp index 916fe2338..9e487cde3 100644 --- a/src/qt/wl_mouse.cpp +++ b/src/qt/wl_mouse.cpp @@ -36,6 +36,7 @@ static zwp_pointer_constraints_v1* conf_pointer_interface = nullptr; static zwp_locked_pointer_v1* conf_pointer = nullptr; static int rel_mouse_x = 0, rel_mouse_y = 0; +static bool wl_init_ok = false; void rel_mouse_event(void* data, zwp_relative_pointer_v1* zwp_relative_pointer_v1, uint32_t tstmp, uint32_t tstmpl, wl_fixed_t dx, wl_fixed_t dy, wl_fixed_t dx_real, wl_fixed_t dy_real) { @@ -92,15 +93,18 @@ static const struct wl_registry_listener registry_listener = { void wl_init() { - wl_display* display = (wl_display*)QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_display"); - if (display) - { - auto registry = wl_display_get_registry(display); - if (registry) + if (!wl_init_ok) { + wl_display* display = (wl_display*)QGuiApplication::platformNativeInterface()->nativeResourceForIntegration("wl_display"); + if (display) { - wl_registry_add_listener(registry, ®istry_listener, nullptr); - wl_display_roundtrip(display); + auto registry = wl_display_get_registry(display); + if (registry) + { + wl_registry_add_listener(registry, ®istry_listener, nullptr); + wl_display_roundtrip(display); + } } + wl_init_ok = true; } } diff --git a/src/thread.cpp b/src/thread.cpp index 6a7af25b8..67bf8d5e6 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -26,6 +26,7 @@ thread_create(void (*thread_rout)(void *param), void *param) int thread_wait(thread_t *arg) { + if (!arg) return 0; auto thread = reinterpret_cast(arg); thread->join(); return 0; diff --git a/src/unix/unix.c b/src/unix/unix.c index 3ab5d46e6..9185fae47 100644 --- a/src/unix/unix.c +++ b/src/unix/unix.c @@ -563,11 +563,12 @@ main_thread(void *param) SDL_Delay(1); /* If needed, handle a screen resize. */ - if (!atomic_flag_test_and_set(&doresize) && !video_fullscreen && !is_quit) { + if (atomic_load(&doresize_monitors[0]) && !video_fullscreen && !is_quit) { if (vid_resize & 2) plat_resize(fixed_size_x, fixed_size_y); else plat_resize(scrnsz_x, scrnsz_y); + atomic_store(&doresize_monitors[0], 1); } } @@ -1114,6 +1115,7 @@ void monitor_thread(void* param) #endif } +extern int gfxcard_2; int main(int argc, char** argv) { SDL_Event event; @@ -1127,6 +1129,7 @@ int main(int argc, char** argv) return 6; } + gfxcard_2 = 0; eventthread = SDL_ThreadID(); blitmtx = SDL_CreateMutex(); if (!blitmtx) diff --git a/src/unix/unix_sdl.c b/src/unix/unix_sdl.c index aeeb9d60c..055867570 100644 --- a/src/unix/unix_sdl.c +++ b/src/unix/unix_sdl.c @@ -128,18 +128,18 @@ sdl_stretch(int *w, int *h, int *x, int *y) void -sdl_blit_shim(int x, int y, int w, int h) +sdl_blit_shim(int x, int y, int w, int h, int monitor_index) { params.x = x; params.y = y; params.w = w; params.h = h; - if (!(!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL))) + if (!(!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL)) || (monitor_index >= 1)) video_copy(interpixels, &(buffer32->line[y][x]), h * 2048 * sizeof(uint32_t)); if (screenshots) video_screenshot(interpixels, 0, 0, 2048); blitreq = 1; - video_blit_complete(); + video_blit_complete_monitor(monitor_index); } void ui_window_title_real(); @@ -516,3 +516,6 @@ wchar_t* ui_window_title(wchar_t* str) #endif return str; } + +void ui_init_monitor(int monitor_index) {} +void ui_deinit_monitor(int monitor_index) {} diff --git a/src/video/vid_ati_mach64.c b/src/video/vid_ati_mach64.c index 2fe70c322..a5325e8f7 100644 --- a/src/video/vid_ati_mach64.c +++ b/src/video/vid_ati_mach64.c @@ -1926,8 +1926,8 @@ static void mach64_vblank_start(svga_t *svga) svga->overlay.x = (mach64->overlay_y_x_start >> 16) & 0x7ff; svga->overlay.y = mach64->overlay_y_x_start & 0x7ff; - svga->overlay.xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x; - svga->overlay.ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y; + svga->overlay.cur_xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x; + svga->overlay.cur_ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y; svga->overlay.addr = mach64->buf_offset[0] & 0x3ffff8; svga->overlay.pitch = mach64->buf_pitch[0] & 0xfff; @@ -3050,7 +3050,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_ARGB1555() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) \ { \ uint16_t dat = ((uint16_t *)src)[x]; \ \ @@ -3069,7 +3069,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_RGB565() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) \ { \ uint16_t dat = ((uint16_t *)src)[x]; \ \ @@ -3088,7 +3088,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_ARGB8888() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) \ { \ int b = src[0]; \ int g = src[1]; \ @@ -3102,7 +3102,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_VYUY422() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x += 2) \ { \ uint8_t y1, y2; \ int8_t u, v; \ @@ -3140,7 +3140,7 @@ uint32_t mach64_readl(uint32_t addr, void *p) #define DECODE_YVYU422() \ do \ { \ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x += 2) \ { \ uint8_t y1, y2; \ int8_t u, v; \ @@ -3217,7 +3217,7 @@ void mach64_overlay_draw(svga_t *svga, int displine) default: mach64_log("Unknown Mach64 scaler format %x\n", mach64->scaler_format); /*Fill buffer with something recognisably wrong*/ - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) mach64->overlay_dat[x] = 0xff00ff; break; } @@ -3225,7 +3225,7 @@ void mach64_overlay_draw(svga_t *svga, int displine) if (overlay_cmp_mix == 2) { - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) { int h = h_acc >> 12; @@ -3238,7 +3238,7 @@ void mach64_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + for (x = 0; x < mach64->svga.overlay_latch.cur_xsize; x++) { int h = h_acc >> 12; int gr_cmp = 0, vid_cmp = 0; @@ -3530,7 +3530,7 @@ static void *mach64_common_init(const device_t *info) mach64_in, mach64_out, NULL, mach64_overlay_draw); - mach64->svga.dac_hwcursor.ysize = 64; + mach64->svga.dac_hwcursor.cur_ysize = 64; if (info->flags & DEVICE_PCI) mem_mapping_disable(&mach64->bios_rom.mapping); diff --git a/src/video/vid_bt48x_ramdac.c b/src/video/vid_bt48x_ramdac.c index 4be070467..43b02fa6e 100644 --- a/src/video/vid_bt48x_ramdac.c +++ b/src/video/vid_bt48x_ramdac.c @@ -169,9 +169,9 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t * ramdac->cmd_r3 = val; if (ramdac->type >= BT485A) bt48x_set_bpp(ramdac, svga); - svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = (val & 4) ? 64 : 32; - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = (val & 4) ? 64 : 32; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; svga->dac_addr = (svga->dac_addr & 0x00ff) | ((val & 0x03) << 8); svga_recalctimings(svga); break; @@ -191,7 +191,7 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t * break; case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ index = svga->dac_addr & da_mask; - if ((ramdac->type >= BT485) && (svga->dac_hwcursor.xsize == 64)) + if ((ramdac->type >= BT485) && (svga->dac_hwcursor.cur_xsize == 64)) cd = (uint8_t *) ramdac->cursor64_data; else { index &= 0xff; @@ -204,19 +204,19 @@ bt48x_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t * break; case 0x0c: /* Cursor X Low Register (RS value = 1100) */ ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; break; case 0x0d: /* Cursor X High Register (RS value = 1101) */ ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; break; case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; break; case 0x0f: /* Cursor Y High Register (RS value = 1111) */ ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; break; } @@ -318,7 +318,7 @@ bt48x_ramdac_in(uint16_t addr, int rs2, int rs3, void *p, svga_t *svga) break; case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ index = (svga->dac_addr - 1) & da_mask; - if ((ramdac->type >= BT485) && (svga->dac_hwcursor.xsize == 64)) + if ((ramdac->type >= BT485) && (svga->dac_hwcursor.cur_xsize == 64)) cd = (uint8_t *) ramdac->cursor64_data; else { index &= 0xff; @@ -376,21 +376,21 @@ bt48x_hwcursor_draw(svga_t *svga, int displine) /* The planes come in two parts, and each plane is 1bpp, so a 32x32 cursor has 4 bytes per line, and a 64x64 cursor has 8 bytes per line. */ - pitch = (svga->dac_hwcursor_latch.xsize >> 3); /* Bytes per line. */ + pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */ /* A 32x32 cursor has 128 bytes per line, and a 64x64 cursor has 512 bytes per line. */ - bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */ + bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */ mode = ramdac->cmd_r2 & 0x03; if (svga->interlace && svga->dac_hwcursor_oddeven) svga->dac_hwcursor_latch.addr += pitch; - if (svga->dac_hwcursor_latch.xsize == 64) + if (svga->dac_hwcursor_latch.cur_xsize == 64) cd = (uint8_t *) ramdac->cursor64_data; else cd = (uint8_t *) ramdac->cursor32_data; - for (x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) { + for (x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += 16) { dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1]; dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | diff --git a/src/video/vid_cga.c b/src/video/vid_cga.c index 9369f1451..d7827732d 100644 --- a/src/video/vid_cga.c +++ b/src/video/vid_cga.c @@ -70,7 +70,7 @@ cga_out(uint16_t addr, uint8_t val, void *p) cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; if (old != val) { if ((cga->crtcreg < 0xe) || (cga->crtcreg > 0x10)) { - fullchange = changeframecount; + cga->fullchange = changeframecount; cga_recalctimings(cga); } } diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index 8c8474f97..b4a7057f0 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -596,7 +596,7 @@ gd54xx_update_overlay(gd54xx_t *gd54xx) svga_t *svga = &gd54xx->svga; int bpp = svga->bpp; - svga->overlay.ysize = gd54xx->overlay.wve - gd54xx->overlay.wvs + 1; + svga->overlay.cur_ysize = gd54xx->overlay.wve - gd54xx->overlay.wvs + 1; gd54xx->overlay.region1size = 32 * gd54xx->overlay.r1sz / bpp + (gd54xx->overlay.r1adjust * 8 / bpp); gd54xx->overlay.region2size = 32 * gd54xx->overlay.r2sz / bpp + (gd54xx->overlay.r2adjust * 8 / bpp); @@ -741,10 +741,10 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga_recalctimings(svga); svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422) - svga->hwcursor.xsize = svga->hwcursor.ysize = + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = ((val & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)) ? 64 : 32; else - svga->hwcursor.xsize = 32; + svga->hwcursor.cur_xsize = 32; if ((svga->seqregs[0x12] & CIRRUS_CURSOR_LARGE) && (svga->crtc[0x27] >= CIRRUS_ID_CLGD5422)) svga->hwcursor.addr = ((gd54xx->vram_size - 0x4000) + ((svga->seqregs[0x13] & 0x3c) * 256)); @@ -1837,7 +1837,7 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) int x, xx, comb, b0, b1; uint8_t dat[2]; int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; - int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; + int pitch = (svga->hwcursor.cur_xsize == 64) ? 16 : 4; uint32_t bgcol = gd54xx->extpallook[0x00]; uint32_t fgcol = gd54xx->extpallook[0x0f]; uint8_t linedbl = svga->dispend * 9 / 10 >= svga->hdisp; @@ -1847,9 +1847,9 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += pitch; - for (x = 0; x < svga->hwcursor.xsize; x += 8) { + for (x = 0; x < svga->hwcursor.cur_xsize; x += 8) { dat[0] = svga->vram[svga->hwcursor_latch.addr & svga->vram_display_mask]; - if (svga->hwcursor.xsize == 64) + if (svga->hwcursor.cur_xsize == 64) dat[1] = svga->vram[(svga->hwcursor_latch.addr + 0x08) & svga->vram_display_mask]; else dat[1] = svga->vram[(svga->hwcursor_latch.addr + 0x80) & svga->vram_display_mask]; @@ -1883,7 +1883,7 @@ void gd54xx_hwcursor_draw(svga_t *svga, int displine) svga->hwcursor_latch.addr++; } - if (svga->hwcursor.xsize == 64) + if (svga->hwcursor.cur_xsize == 64) svga->hwcursor_latch.addr += 8; if (svga->interlace && !svga->hwcursor_oddeven) diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index 81cc34c30..a8f23b7b8 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -111,7 +111,7 @@ ega_out(uint16_t addr, uint8_t val, void *p) if (!ega->attrff) { ega->attraddr = val & 31; if ((val & 0x20) != ega->attr_palette_enable) { - fullchange = 3; + ega->fullchange = 3; ega->attr_palette_enable = val & 0x20; ega_recalctimings(ega); } @@ -119,13 +119,13 @@ ega_out(uint16_t addr, uint8_t val, void *p) o = ega->attrregs[ega->attraddr & 31]; ega->attrregs[ega->attraddr & 31] = val; if (ega->attraddr < 16) - fullchange = changeframecount; + ega->fullchange = changeframecount; if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) { for (c = 0; c < 16; c++) { if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); } - fullchange = changeframecount; + ega->fullchange = changeframecount; } /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ @@ -166,7 +166,7 @@ ega_out(uint16_t addr, uint8_t val, void *p) switch (ega->seqaddr & 0xf) { case 1: if (ega->scrblank && !(val & 0x20)) - fullchange = 3; + ega->fullchange = 3; ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); break; case 2: @@ -232,10 +232,10 @@ ega_out(uint16_t addr, uint8_t val, void *p) if (old != val) { if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) { if ((ega->crtcreg == 0xc) || (ega->crtcreg == 0xd)) { - fullchange = 3; + ega->fullchange = 3; ega->ma_latch = ((ega->crtc[0xc] << 8) | ega->crtc[0xd]) + ((ega->crtc[8] & 0x60) >> 5); } else { - fullchange = changeframecount; + ega->fullchange = changeframecount; ega_recalctimings(ega); } } @@ -588,11 +588,11 @@ ega_poll(void *p) ega->cursoron = ega->blink & (16 + (16 * blink_delay)); if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) - fullchange = 2; + ega->fullchange = 2; ega->blink = (ega->blink + 1) & 0x7f; - if (fullchange) - fullchange--; + if (ega->fullchange) + ega->fullchange--; } if (ega->vc == ega->vsyncstart) { ega->dispon = 0; @@ -773,7 +773,7 @@ ega_write(uint32_t addr, uint8_t val, void *p) return; if (!(ega->gdcreg[6] & 1)) - fullchange = 2; + ega->fullchange = 2; switch (ega->writemode) { case 1: diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index c3ceafc6f..b925ab944 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -123,7 +123,7 @@ ega_render_text_40(ega_t *ega) ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; - if (fullchange) { + if (ega->fullchange) { p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; xinc = (ega->seqregs[1] & 1) ? 16 : 18; @@ -195,7 +195,7 @@ ega_render_text_80(ega_t *ega) ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; - if (fullchange) { + if (ega->fullchange) { p = &buffer32->line[ega->displine + ega->y_add][ega->x_add]; xinc = (ega->seqregs[1] & 1) ? 8 : 9; diff --git a/src/video/vid_et4000w32.c b/src/video/vid_et4000w32.c index 80c48b15f..5a897fcc1 100644 --- a/src/video/vid_et4000w32.c +++ b/src/video/vid_et4000w32.c @@ -269,7 +269,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *p) case 0x210b: case 0x211b: case 0x212b: case 0x213b: case 0x214b: case 0x215b: case 0x216b: case 0x217b: et4000->regs[et4000->index] = val; - svga->hwcursor.xsize = svga->hwcursor.ysize = ((et4000->regs[0xEF] & 4) || (et4000->type == ET4000W32)) ? 128 : 64; + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = ((et4000->regs[0xEF] & 4) || (et4000->type == ET4000W32)) ? 128 : 64; svga->hwcursor.x = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8); svga->hwcursor.y = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8); svga->hwcursor.ena = !!(et4000->regs[0xF7] & 0x80); @@ -284,7 +284,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *p) } } - if (svga->hwcursor.xsize == 128) { + if (svga->hwcursor.cur_xsize == 128) { svga->hwcursor.xoff &= 0x7f; svga->hwcursor.yoff &= 0x7f; if (et4000->type > ET4000W32P_REVC) { @@ -303,7 +303,7 @@ et4000w32p_out(uint16_t addr, uint8_t val, void *p) } svga->hwcursor.addr = (et4000->regs[0xe8] | (et4000->regs[0xe9] << 8) | ((et4000->regs[0xea] & 7) << 16)) << 2; - add2addr = svga->hwcursor.yoff * ((svga->hwcursor.xsize == 128) ? 32 : 16); + add2addr = svga->hwcursor.yoff * ((svga->hwcursor.cur_xsize == 128) ? 32 : 16); svga->hwcursor.addr += add2addr; return; } @@ -1764,8 +1764,8 @@ et4000w32p_hwcursor_draw(svga_t *svga, int displine) et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; int x, offset, xx, xx2; int shift = (et4000->adjust_cursor + 1); - int width = (svga->hwcursor_latch.xsize - svga->hwcursor_latch.xoff); - int pitch = (svga->hwcursor_latch.xsize == 128) ? 32 : 16; + int width = (svga->hwcursor_latch.cur_xsize - svga->hwcursor_latch.xoff); + int pitch = (svga->hwcursor_latch.cur_xsize == 128) ? 32 : 16; int x_acc = 4; int minus_width = 0; uint8_t dat; diff --git a/src/video/vid_hercules.c b/src/video/vid_hercules.c index d310fa419..8e1ab4f8b 100644 --- a/src/video/vid_hercules.c +++ b/src/video/vid_hercules.c @@ -66,6 +66,7 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) hercules_t *dev = (hercules_t *)priv; uint8_t old; + VIDEO_MONITOR_PROLOGUE() switch (addr) { case 0x03b0: case 0x03b2: @@ -92,7 +93,7 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) if (old != val) { if ((dev->crtcreg < 0xe) || (dev->crtcreg > 0x10)) { - fullchange = changeframecount; + dev->fullchange = changeframecount; recalc_timings(dev); } } @@ -146,6 +147,8 @@ hercules_out(uint16_t addr, uint8_t val, void *priv) default: break; } + + VIDEO_MONITOR_EPILOGUE() } @@ -295,6 +298,7 @@ hercules_poll(void *priv) int drawcursor; uint32_t *p; + VIDEO_MONITOR_PROLOGUE() ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; if (! dev->linepos) { @@ -516,6 +520,7 @@ hercules_poll(void *priv) } } } + VIDEO_MONITOR_EPILOGUE() } @@ -527,6 +532,7 @@ hercules_init(const device_t *info) dev = (hercules_t *)malloc(sizeof(hercules_t)); memset(dev, 0x00, sizeof(hercules_t)); + dev->monitor_index = monitor_index_global; overscan_x = 16; overscan_y = 28; diff --git a/src/video/vid_herculesplus.c b/src/video/vid_herculesplus.c index ba981e06a..b4a514422 100644 --- a/src/video/vid_herculesplus.c +++ b/src/video/vid_herculesplus.c @@ -80,14 +80,18 @@ typedef struct { uint16_t ma, maback; int con, coff, cursoron; int dispon, blink; - int vsynctime; + int vsynctime; int vadj; + int monitor_index, prev_monitor_index; int cols[256][2][2]; uint8_t *vram; } herculesplus_t; +#define VIDEO_MONITOR_PROLOGUE() { dev->prev_monitor_index = monitor_index_global; monitor_index_global = dev->monitor_index; } +#define VIDEO_MONITOR_EPILOGUE() { monitor_index_global = dev->prev_monitor_index; } + static video_timings_t timing_herculesplus = {VIDEO_ISA, 8, 16, 32, 8, 16, 32}; @@ -180,7 +184,7 @@ herculesplus_in(uint16_t port, void *priv) break; case 0x3ba: - /* 0x50: InColor card identity */ + /* 0x10: Hercules Plus card identity */ ret = (dev->stat & 0xf) | ((dev->stat & 8) << 4) | 0x10; break; } @@ -489,6 +493,7 @@ herculesplus_poll(void *priv) uint16_t ca = (dev->crtc[15] | (dev->crtc[14] << 8)) & 0x3fff; int x, oldvc, oldsc; + VIDEO_MONITOR_PROLOGUE(); if (! dev->linepos) { timer_advance_u64(&dev->timer, dev->dispofftime); dev->stat |= 1; @@ -602,6 +607,8 @@ herculesplus_poll(void *priv) if ((dev->sc == (dev->crtc[10] & 31) || ((dev->crtc[8] & 3) == 3 && dev->sc == ((dev->crtc[10] & 31) >> 1)))) dev->con = 1; } + + VIDEO_MONITOR_EPILOGUE(); } @@ -615,10 +622,11 @@ herculesplus_init(const device_t *info) memset(dev, 0, sizeof(herculesplus_t)); dev->vram = (uint8_t *)malloc(0x10000); /* 64k VRAM */ + dev->monitor_index = monitor_index_global; timer_add(&dev->timer, herculesplus_poll, dev, 1); - mem_mapping_add(&dev->mapping, 0xb0000, 0x10000, + mem_mapping_add(&dev->mapping, 0xb0000, 0x08000, herculesplus_read,NULL,NULL, herculesplus_write,NULL,NULL, dev->vram, MEM_MAPPING_EXTERNAL, dev); diff --git a/src/video/vid_ht216.c b/src/video/vid_ht216.c index a9b54c1f0..8ef6fc9e0 100644 --- a/src/video/vid_ht216.c +++ b/src/video/vid_ht216.c @@ -1479,7 +1479,7 @@ void break; } - svga->hwcursor.ysize = 32; + svga->hwcursor.cur_ysize = 32; ht216->vram_mask = mem_size - 1; svga->decode_mask = mem_size - 1; diff --git a/src/video/vid_ibm_rgb528_ramdac.c b/src/video/vid_ibm_rgb528_ramdac.c index 98a42b16e..d70732553 100644 --- a/src/video/vid_ibm_rgb528_ramdac.c +++ b/src/video/vid_ibm_rgb528_ramdac.c @@ -636,7 +636,7 @@ ibm_rgb528_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga break; } svga->dac_hwcursor.addr = ramdac->smlc_part; - svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = (val & 0x04) ? 64 : 32; + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = (val & 0x04) ? 64 : 32; svga->dac_hwcursor.ena = ((val & 0x03) != 0x00); break; case 0x031: @@ -681,14 +681,14 @@ ibm_rgb528_ramdac_out(uint16_t addr, int rs2, uint8_t val, void *p, svga_t *svga } break; case 0x035: - if (svga->dac_hwcursor.xsize == 64) + if (svga->dac_hwcursor.cur_xsize == 64) ramdac->cursor_hotspot_x = (val & 0x3f); else ramdac->cursor_hotspot_x = (val & 0x1f); svga->dac_hwcursor.x = ((int) ramdac->hwc_x) - ramdac->cursor_hotspot_x; break; case 0x036: - if (svga->dac_hwcursor.xsize == 64) + if (svga->dac_hwcursor.cur_xsize == 64) ramdac->cursor_hotspot_y = (val & 0x3f); else ramdac->cursor_hotspot_y = (val & 0x1f); @@ -852,7 +852,7 @@ ibm_rgb528_hwcursor_draw(svga_t *svga, int displine) /* The planes come in one part, and each plane is 2bpp, so a 32x32 cursor has 8 bytes per line, and a 64x64 cursor has 16 bytes per line. */ - pitch = (svga->dac_hwcursor_latch.xsize >> 2); /* Bytes per line. */ + pitch = (svga->dac_hwcursor_latch.cur_xsize >> 2); /* Bytes per line. */ if ((ramdac->indexed_data[0x071] & 0x20) && svga->dac_hwcursor_oddeven) svga->dac_hwcursor_latch.addr += pitch; @@ -861,7 +861,7 @@ ibm_rgb528_hwcursor_draw(svga_t *svga, int displine) x_pos = offset + svga->x_add; p = buffer32->line[y_pos]; - for (x = 0; x < svga->dac_hwcursor_latch.xsize; x++) { + for (x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x++) { if (!(x & 3)) four_pixels = ramdac->indexed_data[svga->dac_hwcursor_latch.addr]; diff --git a/src/video/vid_mda.c b/src/video/vid_mda.c index abd6c7c88..0a4ed3c47 100644 --- a/src/video/vid_mda.c +++ b/src/video/vid_mda.c @@ -110,6 +110,8 @@ void mda_poll(void *p) uint8_t chr, attr; int oldsc; int blink; + + VIDEO_MONITOR_PROLOGUE() if (!mda->linepos) { timer_advance_u64(&mda->timer, mda->dispofftime); @@ -252,6 +254,7 @@ void mda_poll(void *p) mda->con = 1; } } + VIDEO_MONITOR_EPILOGUE(); } void mda_init(mda_t *mda) @@ -278,6 +281,7 @@ void mda_init(mda_t *mda) mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; overscan_x = overscan_y = 0; + mda->monitor_index = monitor_index_global; cga_palette = device_get_config_int("rgb_type") << 1; if (cga_palette > 6) diff --git a/src/video/vid_s3.c b/src/video/vid_s3.c index cb968f005..5f849bfbe 100644 --- a/src/video/vid_s3.c +++ b/src/video/vid_s3.c @@ -3250,7 +3250,7 @@ static void s3_trio64v_recalctimings(svga_t *svga) svga->overlay.x = s3->streams.sec_x - s3->streams.pri_x; svga->overlay.y = s3->streams.sec_y - s3->streams.pri_y; - svga->overlay.ysize = s3->streams.sec_h; + svga->overlay.cur_ysize = s3->streams.sec_h; if (s3->streams.buffer_ctrl & 2) svga->overlay.addr = s3->streams.sec_fb1; @@ -7069,7 +7069,7 @@ static void *s3_init(const device_t *info) } } - svga->hwcursor.ysize = 64; + svga->hwcursor.cur_ysize = 64; if (chip == S3_VISION964 && info->local != S3_ELSAWIN2KPROX_964) svga->dac_hwcursor_draw = bt48x_hwcursor_draw; diff --git a/src/video/vid_s3_virge.c b/src/video/vid_s3_virge.c index 662e55379..475269f93 100644 --- a/src/video/vid_s3_virge.c +++ b/src/video/vid_s3_virge.c @@ -830,7 +830,7 @@ static void s3_virge_recalctimings(svga_t *svga) svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; - svga->overlay.ysize = virge->streams.sec_h; + svga->overlay.cur_ysize = virge->streams.sec_h; if (virge->streams.buffer_ctrl & 2) svga->overlay.addr = virge->streams.sec_fb1; @@ -3958,7 +3958,7 @@ static void *s3_virge_init(const device_t *info) s3_virge_in, s3_virge_out, s3_virge_hwcursor_draw, s3_virge_overlay_draw); - virge->svga.hwcursor.ysize = 64; + virge->svga.hwcursor.cur_ysize = 64; if (info->local == S3_VIRGE_GX2) rom_init(&virge->bios_rom, (char *) bios_fn, 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); diff --git a/src/video/vid_sigma.c b/src/video/vid_sigma.c index a6372ad00..9c5474de9 100644 --- a/src/video/vid_sigma.c +++ b/src/video/vid_sigma.c @@ -179,6 +179,7 @@ typedef struct sigma_t int plane; int revision; + int fullchange; } sigma_t; #define COMPOSITE_OLD 0 @@ -228,7 +229,7 @@ sigma_out(uint16_t addr, uint8_t val, void *p) sigma->crtc[sigma->crtcreg] = val & crtcmask[sigma->crtcreg]; if (old != val) { if (sigma->crtcreg < 0xe || sigma->crtcreg > 0x10) { - fullchange = changeframecount; + sigma->fullchange = changeframecount; sigma_recalctimings(sigma); } } diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 6c894b29a..542ab13e0 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -669,34 +669,34 @@ svga_poll(void *p) if (!svga->linepos) { if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { - svga->hwcursor_on = svga->hwcursor.ysize - svga->hwcursor_latch.yoff; + svga->hwcursor_on = svga->hwcursor.cur_ysize - svga->hwcursor_latch.yoff; svga->hwcursor_oddeven = 0; } if (svga->displine == (svga->hwcursor_latch.y + 1) && svga->hwcursor_latch.ena && svga->interlace) { - svga->hwcursor_on = svga->hwcursor.ysize - (svga->hwcursor_latch.yoff + 1); + svga->hwcursor_on = svga->hwcursor.cur_ysize - (svga->hwcursor_latch.yoff + 1); svga->hwcursor_oddeven = 1; } if (svga->displine == svga->dac_hwcursor_latch.y && svga->dac_hwcursor_latch.ena) { - svga->dac_hwcursor_on = svga->dac_hwcursor.ysize - svga->dac_hwcursor_latch.yoff; + svga->dac_hwcursor_on = svga->dac_hwcursor.cur_ysize - svga->dac_hwcursor_latch.yoff; svga->dac_hwcursor_oddeven = 0; } if (svga->displine == (svga->dac_hwcursor_latch.y + 1) && svga->dac_hwcursor_latch.ena && svga->interlace) { - svga->dac_hwcursor_on = svga->dac_hwcursor.ysize - (svga->dac_hwcursor_latch.yoff + 1); + svga->dac_hwcursor_on = svga->dac_hwcursor.cur_ysize - (svga->dac_hwcursor_latch.yoff + 1); svga->dac_hwcursor_oddeven = 1; } if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { - svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_on = svga->overlay_latch.cur_ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 0; } if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { - svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_on = svga->overlay_latch.cur_ysize - svga->overlay_latch.yoff; svga->overlay_oddeven = 1; } @@ -966,9 +966,9 @@ svga_init(const device_t *info, svga_t *svga, void *p, int memsize, svga->hwcursor_draw = hwcursor_draw; svga->overlay_draw = overlay_draw; - svga->hwcursor.xsize = svga->hwcursor.ysize = 32; + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = 32; - svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = 32; + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 32; svga->translate_address = NULL; svga->ksc5601_english_font_type = 0; diff --git a/src/video/vid_table.c b/src/video/vid_table.c index c38154388..fdad852fe 100644 --- a/src/video/vid_table.c +++ b/src/video/vid_table.c @@ -40,6 +40,7 @@ typedef struct { const device_t *device; + int flags; } VIDEO_CARD; @@ -109,13 +110,13 @@ video_cards[] = { { &cpqega_device }, { &ega_device }, { &g2_gc205_device }, - { &hercules_device }, - { &herculesplus_device }, + { &hercules_device, VIDEO_FLAG_TYPE_MDA }, + { &herculesplus_device, VIDEO_FLAG_TYPE_MDA }, { &incolor_device }, { &im1024_device }, { &iskra_ega_device }, { &et4000_kasan_isa_device }, - { &mda_device }, + { &mda_device, VIDEO_FLAG_TYPE_MDA }, { &genius_device }, { &nga_device }, { &ogc_device }, @@ -275,6 +276,10 @@ vid_table_log(const char *fmt, ...) void video_reset_close(void) { + for (int i = 1; i < MONITORS_NUM; i++) + video_monitor_close(i); + + monitor_index_global = 0; video_inform(VIDEO_FLAG_TYPE_NONE, &timing_default); was_reset = 0; } @@ -289,16 +294,18 @@ video_prepare(void) fontdatksc5601 = NULL; } - /* Reset the CGA palette. */ - cga_palette = 0; - cgapal_rebuild(); - /* Reset the blend. */ herc_blend = 0; - /* Do an inform on the default values, so that that there's some sane values initialized - even if the device init function does not do an inform of its own. */ - video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_default); + for (int i = 0; i < MONITORS_NUM; i++) { + /* Reset the CGA palette. */ + if (monitors[i].mon_cga_palette) *monitors[i].mon_cga_palette = 0; + cgapal_rebuild_monitor(i); + + /* Do an inform on the default values, so that that there's some sane values initialized + even if the device init function does not do an inform of its own. */ + video_inform_monitor(VIDEO_FLAG_TYPE_SPECIAL, &timing_default, i); + } } @@ -321,6 +328,7 @@ video_reset(int card) vid_table_log("VIDEO: reset (gfxcard=%d, internal=%d)\n", card, machine_has_flags(machine, MACHINE_VIDEO) ? 1 : 0); + monitor_index_global = 0; loadfont("roms/video/mda/mda.rom", 0); /* Do not initialize internal cards here. */ @@ -334,6 +342,17 @@ video_reset(int card) device_add(video_cards[card].device); } + if (!(card == VID_NONE) + && !machine_has_flags(machine, MACHINE_VIDEO_ONLY) + && gfxcard_2 != 0 + && (video_cards[gfxcard_2].flags != video_cards[gfxcard].flags) + && device_is_valid(video_card_getdevice(gfxcard_2), machine)) { + video_monitor_init(1); + monitor_index_global = 1; + device_add(video_cards[gfxcard_2].device); + monitor_index_global = 0; + } + /* Enable the Voodoo if configured. */ if (voodoo_enabled) device_add(&voodoo_device); @@ -351,6 +370,11 @@ video_card_available(int card) return(1); } +int +video_card_get_flags(int card) +{ + return video_cards[card].flags; +} const device_t * video_card_getdevice(int card) diff --git a/src/video/vid_tgui9440.c b/src/video/vid_tgui9440.c index 9cf7e1ff7..603acccb9 100644 --- a/src/video/vid_tgui9440.c +++ b/src/video/vid_tgui9440.c @@ -503,7 +503,7 @@ tgui_out(uint16_t addr, uint8_t val, void *p) case 0x50: if (tgui->type >= TGUI_9440) { svga->hwcursor.ena = !!(val & 0x80); - svga->hwcursor.xsize = svga->hwcursor.ysize = ((val & 1) ? 64 : 32); + svga->hwcursor.cur_xsize = svga->hwcursor.cur_ysize = ((val & 1) ? 64 : 32); } break; } @@ -887,7 +887,7 @@ tgui_hwcursor_draw(svga_t *svga, int displine) uint32_t dat[2]; int xx; int offset = svga->hwcursor_latch.x + svga->hwcursor_latch.xoff; - int pitch = (svga->hwcursor_latch.xsize == 64) ? 16 : 8; + int pitch = (svga->hwcursor_latch.cur_xsize == 64) ? 16 : 8; if (svga->interlace && svga->hwcursor_oddeven) svga->hwcursor_latch.addr += pitch; diff --git a/src/video/vid_tvp3026_ramdac.c b/src/video/vid_tvp3026_ramdac.c index 6218998e5..580e96990 100644 --- a/src/video/vid_tvp3026_ramdac.c +++ b/src/video/vid_tvp3026_ramdac.c @@ -154,9 +154,9 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t case 0x09: /* Direct Cursor Control (RS value = 1001) */ ramdac->dcc = val; if (ramdac->ccr & 0x80) { - svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = 64; - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; svga->dac_hwcursor.ena = !!(val & 0x03); ramdac->mode = val & 0x03; } @@ -165,9 +165,9 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t switch (ramdac->ind_idx) { case 0x06: /* Indirect Cursor Control */ ramdac->ccr = val; - svga->dac_hwcursor.xsize = svga->dac_hwcursor.ysize = 64; - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.cur_xsize = svga->dac_hwcursor.cur_ysize = 64; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; svga->dac_hwcursor.ena = !!(val & 0x03); ramdac->mode = val & 0x03; break; @@ -254,19 +254,19 @@ tvp3026_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, void *p, svga_t break; case 0x0c: /* Cursor X Low Register (RS value = 1100) */ ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; break; case 0x0d: /* Cursor X High Register (RS value = 1101) */ ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); - svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.xsize; + svga->dac_hwcursor.x = ramdac->hwc_x - svga->dac_hwcursor.cur_xsize; break; case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; break; case 0x0f: /* Cursor Y High Register (RS value = 1111) */ ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); - svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.ysize; + svga->dac_hwcursor.y = ramdac->hwc_y - svga->dac_hwcursor.cur_ysize; break; } @@ -464,10 +464,10 @@ tvp3026_hwcursor_draw(svga_t *svga, int displine) /* The planes come in two parts, and each plane is 1bpp, so a 32x32 cursor has 4 bytes per line, and a 64x64 cursor has 8 bytes per line. */ - pitch = (svga->dac_hwcursor_latch.xsize >> 3); /* Bytes per line. */ + pitch = (svga->dac_hwcursor_latch.cur_xsize >> 3); /* Bytes per line. */ /* A 32x32 cursor has 128 bytes per line, and a 64x64 cursor has 512 bytes per line. */ - bppl = (pitch * svga->dac_hwcursor_latch.ysize); /* Bytes per plane. */ + bppl = (pitch * svga->dac_hwcursor_latch.cur_ysize); /* Bytes per plane. */ mode = ramdac->mode; if (svga->interlace && svga->dac_hwcursor_oddeven) @@ -475,7 +475,7 @@ tvp3026_hwcursor_draw(svga_t *svga, int displine) cd = (uint8_t *) ramdac->cursor64_data; - for (x = 0; x < svga->dac_hwcursor_latch.xsize; x += 16) { + for (x = 0; x < svga->dac_hwcursor_latch.cur_xsize; x += 16) { dat[0] = (cd[svga->dac_hwcursor_latch.addr] << 8) | cd[svga->dac_hwcursor_latch.addr + 1]; dat[1] = (cd[svga->dac_hwcursor_latch.addr + bppl] << 8) | diff --git a/src/video/vid_voodoo_banshee.c b/src/video/vid_voodoo_banshee.c index 020cb65a4..42b06eb4b 100644 --- a/src/video/vid_voodoo_banshee.c +++ b/src/video/vid_voodoo_banshee.c @@ -547,12 +547,12 @@ static void banshee_recalctimings(svga_t *svga) svga->overlay.x = voodoo->overlay.start_x; svga->overlay.y = voodoo->overlay.start_y; - svga->overlay.xsize = voodoo->overlay.size_x; - svga->overlay.ysize = voodoo->overlay.size_y; + svga->overlay.cur_xsize = voodoo->overlay.size_x; + svga->overlay.cur_ysize = voodoo->overlay.size_y; svga->overlay.pitch = (banshee->vidDesktopOverlayStride & VID_STRIDE_OVERLAY_MASK) >> VID_STRIDE_OVERLAY_SHIFT; if (banshee->vidProcCfg & VIDPROCCFG_OVERLAY_TILE) svga->overlay.pitch *= 128*32; - if (svga->overlay.xsize <= 0 || svga->overlay.ysize <= 0) + if (svga->overlay.cur_xsize <= 0 || svga->overlay.cur_ysize <= 0) svga->overlay.ena = 0; if (svga->overlay.ena) { @@ -739,8 +739,8 @@ static void banshee_ext_outl(uint16_t addr, uint32_t val, void *p) else svga->hwcursor.yoff = 0; svga->hwcursor.addr = (banshee->hwCurPatAddr & 0xfffff0) + (svga->hwcursor.yoff * 16); - svga->hwcursor.xsize = 64; - svga->hwcursor.ysize = 64; + svga->hwcursor.cur_xsize = 64; + svga->hwcursor.cur_ysize = 64; // banshee_log("hwCurLoc %08x %i\n", val, svga->hwcursor.y); break; case Video_hwCurC0: @@ -2103,7 +2103,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) OVERLAY_SAMPLE(banshee->overlay_buffer[1]); if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { unsigned int x_coeff = (src_x & 0xfffff) >> 4; unsigned int coeffs[4] = { @@ -2135,7 +2135,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { uint32_t samp0 = banshee->overlay_buffer[0][src_x >> 20]; uint32_t samp1 = banshee->overlay_buffer[1][src_x >> 20]; @@ -2153,12 +2153,12 @@ static void banshee_overlay_draw(svga_t *svga, int displine) case VIDPROCCFG_FILTER_MODE_DITHER_4X4: if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) { - uint8_t *fil = malloc((svga->overlay_latch.xsize) * 3); - uint8_t *fil3 = malloc((svga->overlay_latch.xsize) * 3); + uint8_t *fil = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *fil3 = malloc((svga->overlay_latch.cur_xsize) * 3); if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* leilei HACK - don't know of real 4x1 hscaled behavior yet, double for now */ { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { fil[x*3] = ((banshee->overlay_buffer[0][src_x >> 20])); fil[x*3+1] = ((banshee->overlay_buffer[0][src_x >> 20] >> 8)); @@ -2171,7 +2171,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { fil[x*3] = ((banshee->overlay_buffer[0][x])); fil[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); @@ -2183,7 +2183,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } if (y % 2 == 0) { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { fil[x*3] = banshee->voodoo->purpleline[fil[x*3+0]][0]; fil[x*3+1] = banshee->voodoo->purpleline[fil[x*3+1]][1]; @@ -2191,25 +2191,25 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } } - for (x=1; xoverlay_latch.xsize;x++) + for (x=1; xoverlay_latch.cur_xsize;x++) { fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; } - for (x=1; xoverlay_latch.xsize;x++) + for (x=1; xoverlay_latch.cur_xsize;x++) { fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x-1) *3]]; fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x-1) *3+1]]; fil[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil3[(x-1) *3+2]]; } - for (x=1; xoverlay_latch.xsize;x++) + for (x=1; xoverlay_latch.cur_xsize;x++) { fil3[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil[(x-1) *3]]; fil3[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil[(x-1) *3+1]]; fil3[(x)*3+2] = vb_filter_v1_rb [fil[x*3+2]] [fil[(x-1) *3+2]]; } - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { fil[(x)*3] = vb_filter_v1_rb [fil[x*3]] [fil3[(x+1) *3]]; fil[(x)*3+1] = vb_filter_v1_g [fil[x*3+1]][fil3[(x+1) *3+1]]; @@ -2224,7 +2224,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) { if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; src_x += voodoo->overlay.vidOverlayDudx; @@ -2232,7 +2232,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } } @@ -2241,18 +2241,18 @@ static void banshee_overlay_draw(svga_t *svga, int displine) case VIDPROCCFG_FILTER_MODE_DITHER_2X2: if (banshee->voodoo->scrfilter && banshee->voodoo->scrfilterEnabled) { - uint8_t *fil = malloc((svga->overlay_latch.xsize) * 3); - uint8_t *soak = malloc((svga->overlay_latch.xsize) * 3); - uint8_t *soak2 = malloc((svga->overlay_latch.xsize) * 3); + uint8_t *fil = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *soak = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *soak2 = malloc((svga->overlay_latch.cur_xsize) * 3); - uint8_t *samp1 = malloc((svga->overlay_latch.xsize) * 3); - uint8_t *samp2 = malloc((svga->overlay_latch.xsize) * 3); - uint8_t *samp3 = malloc((svga->overlay_latch.xsize) * 3); - uint8_t *samp4 = malloc((svga->overlay_latch.xsize) * 3); + uint8_t *samp1 = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *samp2 = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *samp3 = malloc((svga->overlay_latch.cur_xsize) * 3); + uint8_t *samp4 = malloc((svga->overlay_latch.cur_xsize) * 3); src = &svga->vram[src_addr2 & svga->vram_mask]; OVERLAY_SAMPLE(banshee->overlay_buffer[1]); - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { samp1[x*3] = ((banshee->overlay_buffer[0][x])); samp1[x*3+1] = ((banshee->overlay_buffer[0][x] >> 8)); @@ -2289,7 +2289,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) /* 2x2 on a scaled low res */ { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { p[x] = (fil[(src_x >> 20)*3+2] << 16) | (fil[(src_x >> 20)*3+1] << 8) | fil[(src_x >> 20)*3]; src_x += voodoo->overlay.vidOverlayDudx; @@ -2297,7 +2297,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x=0; xoverlay_latch.xsize;x++) + for (x=0; xoverlay_latch.cur_xsize;x++) { p[x] = (fil[x*3+2] << 16) | (fil[x*3+1] << 8) | fil[x*3]; } @@ -2315,7 +2315,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) { if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; @@ -2324,7 +2324,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } } @@ -2334,7 +2334,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) default: if (banshee->vidProcCfg & VIDPROCCFG_H_SCALE_ENABLE) { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) { p[x] = banshee->overlay_buffer[0][src_x >> 20]; @@ -2343,7 +2343,7 @@ static void banshee_overlay_draw(svga_t *svga, int displine) } else { - for (x = 0; x < svga->overlay_latch.xsize; x++) + for (x = 0; x < svga->overlay_latch.cur_xsize; x++) p[x] = banshee->overlay_buffer[0][x]; } break; diff --git a/src/video/vid_xga.c b/src/video/vid_xga.c index 8edb7cca2..60e6f3d67 100644 --- a/src/video/vid_xga.c +++ b/src/video/vid_xga.c @@ -2048,7 +2048,7 @@ xga_hwcursor_draw(svga_t *svga, int displine) x_pos = offset + svga->x_add; p = buffer32->line[y_pos]; - for (x = 0; x < xga->hwcursor_latch.xsize; x++) { + for (x = 0; x < xga->hwcursor_latch.cur_xsize; x++) { if (x >= idx) { if (!(x & 0x03)) dat = xga->sprite_data[xga->hwcursor_latch.addr & 0x3ff]; @@ -2476,13 +2476,13 @@ xga_poll(xga_t *xga, svga_t *svga) if (!xga->linepos) { if (xga->displine == xga->hwcursor_latch.y && xga->hwcursor_latch.ena) { - xga->hwcursor_on = xga->hwcursor_latch.ysize - (xga->cursor_data_on ? 32 : 0); + xga->hwcursor_on = xga->hwcursor_latch.cur_ysize - (xga->cursor_data_on ? 32 : 0); xga->hwcursor_oddeven = 0; } if (xga->displine == (xga->hwcursor_latch.y + 1) && xga->hwcursor_latch.ena && xga->interlace) { - xga->hwcursor_on = xga->hwcursor_latch.ysize - (xga->cursor_data_on ? 33 : 1); + xga->hwcursor_on = xga->hwcursor_latch.cur_ysize - (xga->cursor_data_on ? 33 : 1); xga->hwcursor_oddeven = 1; } @@ -2702,8 +2702,8 @@ static void xga->vram = calloc(xga->vram_size, 1); xga->changedvram = calloc(xga->vram_size >> 12, 1); xga->on = 0; - xga->hwcursor.xsize = 64; - xga->hwcursor.ysize = 64; + xga->hwcursor.cur_xsize = 64; + xga->hwcursor.cur_ysize = 64; xga->bios_rom.sz = 0x8000; f = rom_fopen(xga->type ? XGA2_BIOS_PATH : XGA_BIOS_PATH, "rb"); diff --git a/src/video/video.c b/src/video/video.c index f58b29c84..ec56c574c 100644 --- a/src/video/video.c +++ b/src/video/video.c @@ -48,6 +48,7 @@ * Copyright 2008-2019 Sarah Walker. * Copyright 2016-2019 Miran Grca. */ +#include #define PNG_DEBUG 0 #include #include @@ -68,6 +69,7 @@ #include <86box/timer.h> #include <86box/path.h> #include <86box/plat.h> +#include <86box/ui.h> #include <86box/thread.h> #include <86box/video.h> #include <86box/vid_svga.h> @@ -75,7 +77,7 @@ #include volatile int screenshots = 0; -bitmap_t *buffer32 = NULL; +//bitmap_t *buffer32 = NULL; uint8_t fontdat[2048][8]; /* IBM CGA font */ uint8_t fontdatm[2048][16]; /* IBM MDA font */ uint8_t fontdatw[512][32]; /* Wyse700 font */ @@ -83,31 +85,15 @@ uint8_t fontdat8x12[256][16]; /* MDSI Genius font */ uint8_t fontdat12x18[256][36]; /* IM1024 font */ dbcs_font_t *fontdatksc5601 = NULL; /* Korean KSC-5601 font */ dbcs_font_t *fontdatksc5601_user = NULL; /* Korean KSC-5601 user defined font */ -uint32_t pal_lookup[256]; -int xsize = 1, - ysize = 1; -int cga_palette = 0, - herc_blend = 0; +int herc_blend = 0; uint32_t *video_6to8 = NULL, *video_8togs = NULL, *video_8to32 = NULL, *video_15to32 = NULL, - *video_16to32 = NULL; -int changeframecount = 2; + *video_16to32 = NULL; int frames = 0; int fullchange = 0; uint8_t edatlookup[4][4]; -int overscan_x = 0, - overscan_y = 0; -int video_timing_read_b = 0, - video_timing_read_w = 0, - video_timing_read_l = 0; -int video_timing_write_b = 0, - video_timing_write_w = 0, - video_timing_write_l = 0; -int video_res_x = 0, - video_res_y = 0, - video_bpp = 0; static int video_force_resize; int video_grayscale = 0; int video_graytype = 0; @@ -115,6 +101,10 @@ static int vid_type; static const video_timings_t *vid_timings; static uint32_t cga_2_table[16]; static uint8_t thread_run = 0; +monitor_t monitors[MONITORS_NUM]; +monitor_settings_t monitor_settings[MONITORS_NUM]; +atomic_bool doresize_monitors[MONITORS_NUM]; +int monitor_index_global = 0; #ifdef _WIN32 void * __cdecl (*video_copy)(void *_Dst, const void *_Src, size_t _Size) = memcpy; @@ -251,10 +241,12 @@ const uint32_t shade[5][256] = }; -static struct { +static struct blit_data_struct { int x, y, w, h; int busy; int buffer_in_use; + int thread_run; + int monitor_index; thread_t *blit_thread; event_t *wake_blit_thread; @@ -263,7 +255,7 @@ static struct { } blit_data; -static void (*blit_func)(int x, int y, int w, int h); +static void (*blit_func)(int x, int y, int w, int h, int monitor_index); #ifdef ENABLE_VIDEO_LOG @@ -287,7 +279,7 @@ video_log(const char *fmt, ...) void -video_setblit(void(*blit)(int,int,int,int)) +video_setblit(void(*blit)(int,int,int,int,int)) { blit_func = blit; } @@ -296,41 +288,68 @@ video_setblit(void(*blit)(int,int,int,int)) void video_blit_complete(void) { - blit_data.buffer_in_use = 0; - - thread_set_event(blit_data.buffer_not_in_use); + video_blit_complete_monitor(monitor_index_global); } void video_wait_for_blit(void) { - while (blit_data.busy) - thread_wait_event(blit_data.blit_complete, -1); - thread_reset_event(blit_data.blit_complete); + video_wait_for_blit_monitor(monitor_index_global); } void video_wait_for_buffer(void) { - while (blit_data.buffer_in_use) - thread_wait_event(blit_data.buffer_not_in_use, -1); - thread_reset_event(blit_data.buffer_not_in_use); + video_wait_for_buffer_monitor(monitor_index_global); } -static png_structp png_ptr; -static png_infop info_ptr; +void +video_blit_complete_monitor(int monitor_index) +{ + struct blit_data_struct* blit_data_ptr = monitors[monitor_index].mon_blit_data_ptr; + blit_data_ptr->buffer_in_use = 0; + + thread_set_event(blit_data_ptr->buffer_not_in_use); +} + + +void +video_wait_for_blit_monitor(int monitor_index) +{ + struct blit_data_struct* blit_data_ptr = monitors[monitor_index].mon_blit_data_ptr; + + while (blit_data_ptr->busy) + thread_wait_event(blit_data_ptr->blit_complete, -1); + thread_reset_event(blit_data_ptr->blit_complete); +} + + +void +video_wait_for_buffer_monitor(int monitor_index) +{ + struct blit_data_struct* blit_data_ptr = monitors[monitor_index].mon_blit_data_ptr; + + while (blit_data_ptr->buffer_in_use) + thread_wait_event(blit_data_ptr->buffer_not_in_use, -1); + thread_reset_event(blit_data_ptr->buffer_not_in_use); +} + + +static png_structp png_ptr[MONITORS_NUM]; +static png_infop info_ptr[MONITORS_NUM]; static void -video_take_screenshot(const char *fn, uint32_t *buf, int start_x, int start_y, int row_len) +video_take_screenshot_monitor(const char *fn, uint32_t *buf, int start_x, int start_y, int row_len, int monitor_index) { int i, x, y; png_bytep *b_rgb = NULL; FILE *fp = NULL; uint32_t temp = 0x00000000; + struct blit_data_struct* blit_data_ptr = monitors[monitor_index].mon_blit_data_ptr; /* create file */ fp = plat_fopen((char *) fn, (char *) "wb"); @@ -340,37 +359,37 @@ video_take_screenshot(const char *fn, uint32_t *buf, int start_x, int start_y, i } /* initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_ptr[monitor_index] = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - if (!png_ptr) { + if (!png_ptr[monitor_index]) { video_log("[video_take_screenshot] png_create_write_struct failed"); fclose(fp); return; } - info_ptr = png_create_info_struct(png_ptr); - if (!info_ptr) { + info_ptr[monitor_index] = png_create_info_struct(png_ptr[monitor_index]); + if (!info_ptr[monitor_index]) { video_log("[video_take_screenshot] png_create_info_struct failed"); fclose(fp); return; } - png_init_io(png_ptr, fp); + png_init_io(png_ptr[monitor_index], fp); - png_set_IHDR(png_ptr, info_ptr, blit_data.w, blit_data.h, + png_set_IHDR(png_ptr[monitor_index], info_ptr[monitor_index], blit_data_ptr->w, blit_data_ptr->h, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * blit_data.h); + b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * blit_data_ptr->h); if (b_rgb == NULL) { video_log("[video_take_screenshot] Unable to Allocate RGB Bitmap Memory"); fclose(fp); return; } - for (y = 0; y < blit_data.h; ++y) { - b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); - for (x = 0; x < blit_data.w; ++x) { + for (y = 0; y < blit_data_ptr->h; ++y) { + b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr[monitor_index], info_ptr[monitor_index])); + for (x = 0; x < blit_data_ptr->w; ++x) { if (buf == NULL) memset(&(b_rgb[y][x * 3]), 0x00, 3); else { @@ -382,14 +401,14 @@ video_take_screenshot(const char *fn, uint32_t *buf, int start_x, int start_y, i } } - png_write_info(png_ptr, info_ptr); + png_write_info(png_ptr[monitor_index], info_ptr[monitor_index]); - png_write_image(png_ptr, b_rgb); + png_write_image(png_ptr[monitor_index], b_rgb); - png_write_end(png_ptr, NULL); + png_write_end(png_ptr[monitor_index], NULL); /* cleanup heap allocation */ - for (i = 0; i < blit_data.h; i++) + for (i = 0; i < blit_data_ptr->h; i++) if (b_rgb[i]) free(b_rgb[i]); if (b_rgb) free(b_rgb); @@ -399,9 +418,9 @@ video_take_screenshot(const char *fn, uint32_t *buf, int start_x, int start_y, i void -video_screenshot(uint32_t *buf, int start_x, int start_y, int row_len) +video_screenshot_monitor(uint32_t *buf, int start_x, int start_y, int row_len, int monitor_index) { - char path[1024], fn[128]; + char path[1024], fn[256]; memset(fn, 0, sizeof(fn)); memset(path, 0, sizeof(path)); @@ -409,19 +428,27 @@ video_screenshot(uint32_t *buf, int start_x, int start_y, int row_len) path_append_filename(path, usr_path, SCREENSHOT_PATH); if (! plat_dir_check(path)) - plat_dir_create(path); + plat_dir_create(path); path_slash(path); + strcat(path, "Monitor_"); + snprintf(&path[strlen(path)], 42, "%d_", monitor_index + 1); plat_tempfile(fn, NULL, ".png"); strcat(path, fn); video_log("taking screenshot to: %s\n", path); - video_take_screenshot((const char *) path, buf, start_x, start_y, row_len); - png_destroy_write_struct(&png_ptr, &info_ptr); + video_take_screenshot_monitor((const char *) path, buf, start_x, start_y, row_len, monitor_index); + png_destroy_write_struct(&png_ptr[monitor_index], &info_ptr[monitor_index]); - screenshots--; + monitors[monitor_index].mon_screenshots--; +} + +void +video_screenshot(uint32_t *buf, int start_x, int start_y, int row_len) +{ + video_screenshot_monitor(buf, start_x, start_y, row_len, 0); } @@ -454,40 +481,48 @@ video_transform_copy(void *__restrict _Dst, const void *__restrict _Src, size_t static void blit_thread(void *param) { - while (thread_run) { - thread_wait_event(blit_data.wake_blit_thread, -1); - thread_reset_event(blit_data.wake_blit_thread); + struct blit_data_struct* data = param; + while (data->thread_run) { + thread_wait_event(data->wake_blit_thread, -1); + thread_reset_event(data->wake_blit_thread); MTR_BEGIN("video", "blit_thread"); if (blit_func) - blit_func(blit_data.x, blit_data.y, blit_data.w, blit_data.h); + blit_func(data->x, data->y, data->w, data->h, data->monitor_index); - blit_data.busy = 0; + data->busy = 0; MTR_END("video", "blit_thread"); - thread_set_event(blit_data.blit_complete); + thread_set_event(data->blit_complete); } } void video_blit_memtoscreen(int x, int y, int w, int h) +{ + video_blit_memtoscreen_monitor(x, y, w, h, monitor_index_global); +} + + +void +video_blit_memtoscreen_monitor(int x, int y, int w, int h, int monitor_index) { MTR_BEGIN("video", "video_blit_memtoscreen"); if ((w <= 0) || (h <= 0)) - return; + return; - video_wait_for_blit(); + video_wait_for_blit_monitor(monitor_index); - blit_data.busy = 1; - blit_data.buffer_in_use = 1; - blit_data.x = x; - blit_data.y = y; - blit_data.w = w; - blit_data.h = h; + monitors[monitor_index].mon_blit_data_ptr->busy = 1; + monitors[monitor_index].mon_blit_data_ptr->buffer_in_use = 1; + monitors[monitor_index].mon_blit_data_ptr->x = x; + monitors[monitor_index].mon_blit_data_ptr->y = y; + monitors[monitor_index].mon_blit_data_ptr->w = w; + monitors[monitor_index].mon_blit_data_ptr->h = h; - thread_set_event(blit_data.wake_blit_thread); + thread_set_event(monitors[monitor_index].mon_blit_data_ptr->wake_blit_thread); MTR_END("video", "video_blit_memtoscreen"); } @@ -521,7 +556,7 @@ uint32_t pixel_to_color(uint8_t *pixels32, uint8_t pos) void -video_blend(int x, int y) +video_blend_monitor(int x, int y, int monitor_index) { int xx; uint32_t pixels32_1, pixels32_2; @@ -529,152 +564,212 @@ video_blend(int x, int y) static unsigned int carry = 0; if (!herc_blend) - return; + return; if (!x) - carry = 0; + carry = 0; - val1 = pixels8(&(buffer32->line[y][x])); + val1 = pixels8(&(monitors[monitor_index].target_buffer->line[y][x])); val2 = (val1 >> 1) + carry; carry = (val1 & 1) << 7; pixels32_1 = cga_2_table[val1 >> 4] + cga_2_table[val2 >> 4]; pixels32_2 = cga_2_table[val1 & 0xf] + cga_2_table[val2 & 0xf]; for (xx = 0; xx < 4; xx++) { - buffer32->line[y][x + xx] = pixel_to_color((uint8_t *) &pixels32_1, xx); - buffer32->line[y][x + (xx | 4)] = pixel_to_color((uint8_t *) &pixels32_2, xx); + monitors[monitor_index].target_buffer->line[y][x + xx] = pixel_to_color((uint8_t *) &pixels32_1, xx); + monitors[monitor_index].target_buffer->line[y][x + (xx | 4)] = pixel_to_color((uint8_t *) &pixels32_2, xx); } } +void +video_blend(int x, int y) +{ + video_blend_monitor(x, y, monitor_index_global); +} + + +void +video_blit_memtoscreen_8_monitor(int x, int y, int w, int h, int monitor_index) +{ + int yy, xx; + + if ((w > 0) && (h > 0)) { + for (yy = 0; yy < h; yy++) { + if ((y + yy) >= 0 && (y + yy) < monitors[monitor_index].target_buffer->h) { + for (xx = 0; xx < w; xx++) { + if (monitors[monitor_index].target_buffer->line[y + yy][x + xx] <= 0xff) + monitors[monitor_index].target_buffer->line[y + yy][x + xx] = monitors[monitor_index].mon_pal_lookup[monitors[monitor_index].target_buffer->line[y + yy][x + xx]]; + else + monitors[monitor_index].target_buffer->line[y + yy][x + xx] = 0x00000000; + } + } + } + } + + video_blit_memtoscreen_monitor(x, y, w, h, monitor_index); +} + + void video_blit_memtoscreen_8(int x, int y, int w, int h) { - int yy, xx; - - if ((w > 0) && (h > 0)) { - for (yy = 0; yy < h; yy++) { - if ((y + yy) >= 0 && (y + yy) < buffer32->h) { - for (xx = 0; xx < w; xx++) { - if (buffer32->line[y + yy][x + xx] <= 0xff) - buffer32->line[y + yy][x + xx] = pal_lookup[buffer32->line[y + yy][x + xx]]; - else - buffer32->line[y + yy][x + xx] = 0x00000000; - } - } - } - } - - video_blit_memtoscreen(x, y, w, h); + video_blit_memtoscreen_8_monitor(x, y, w, h, monitor_index_global); } void -cgapal_rebuild(void) +cgapal_rebuild_monitor(int monitor_index) { int c; + uint32_t* palette_lookup = monitors[monitor_index].mon_pal_lookup; + int cga_palette_monitor = 0; /* We cannot do this (yet) if we have not been enabled yet. */ if (video_6to8 == NULL) return; + if (monitors[monitor_index].target_buffer == NULL || + monitors[monitor_index].mon_cga_palette == NULL) return; + + cga_palette_monitor = *monitors[monitor_index].mon_cga_palette; + for (c=0; c<256; c++) { - pal_lookup[c] = makecol(video_6to8[cgapal[c].r], + palette_lookup[c] = makecol(video_6to8[cgapal[c].r], video_6to8[cgapal[c].g], video_6to8[cgapal[c].b]); } - if ((cga_palette > 1) && (cga_palette < 7)) { + if ((cga_palette_monitor > 1) && (cga_palette_monitor < 7)) { if (vid_cga_contrast != 0) { for (c = 0; c < 16; c++) { - pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], - video_6to8[cgapal_mono[cga_palette - 2][c].g], - video_6to8[cgapal_mono[cga_palette - 2][c].b]); - pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], - video_6to8[cgapal_mono[cga_palette - 2][c].g], - video_6to8[cgapal_mono[cga_palette - 2][c].b]); - pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], - video_6to8[cgapal_mono[cga_palette - 2][c].g], - video_6to8[cgapal_mono[cga_palette - 2][c].b]); - pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], - video_6to8[cgapal_mono[cga_palette - 2][c].g], - video_6to8[cgapal_mono[cga_palette - 2][c].b]); + palette_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 2][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].b]); + palette_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 2][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].b]); + palette_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 2][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].b]); + palette_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 2][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 2][c].b]); } } else { for (c = 0; c < 16; c++) { - pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], - video_6to8[cgapal_mono[cga_palette - 1][c].g], - video_6to8[cgapal_mono[cga_palette - 1][c].b]); - pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], - video_6to8[cgapal_mono[cga_palette - 1][c].g], - video_6to8[cgapal_mono[cga_palette - 1][c].b]); - pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], - video_6to8[cgapal_mono[cga_palette - 1][c].g], - video_6to8[cgapal_mono[cga_palette - 1][c].b]); - pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], - video_6to8[cgapal_mono[cga_palette - 1][c].g], - video_6to8[cgapal_mono[cga_palette - 1][c].b]); + palette_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 1][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].b]); + palette_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 1][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].b]); + palette_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 1][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].b]); + palette_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette_monitor - 1][c].r], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].g], + video_6to8[cgapal_mono[cga_palette_monitor - 1][c].b]); } } } - if (cga_palette == 7) - pal_lookup[0x16] = makecol(video_6to8[42],video_6to8[42],video_6to8[0]); + if (cga_palette_monitor == 7) + palette_lookup[0x16] = makecol(video_6to8[42],video_6to8[42],video_6to8[0]); +} + +void +cgapal_rebuild(void) +{ + cgapal_rebuild_monitor(monitor_index_global); +} + + +void +video_inform_monitor(int type, const video_timings_t *ptr, int monitor_index) +{ + monitor_t* monitor = &monitors[monitor_index]; + monitor->mon_vid_type = type; + monitor->mon_vid_timings = ptr; } void video_inform(int type, const video_timings_t *ptr) { - vid_type = type; - vid_timings = ptr; + video_inform_monitor(type, ptr, monitor_index_global); +} + + +int +video_get_type_monitor(int monitor_index) +{ + return monitors[monitor_index].mon_vid_type; } int video_get_type(void) { - return vid_type; + return video_get_type_monitor(0); } void video_update_timing(void) { - if (!vid_timings) - return; + const video_timings_t* monitor_vid_timings = NULL; + int *vid_timing_read_b = NULL; + int *vid_timing_read_l = NULL; + int *vid_timing_read_w = NULL; + int *vid_timing_write_b = NULL; + int *vid_timing_write_l = NULL; + int *vid_timing_write_w = NULL; + int i = 0; - if (vid_timings->type == VIDEO_ISA) { - video_timing_read_b = ISA_CYCLES(vid_timings->read_b); - video_timing_read_w = ISA_CYCLES(vid_timings->read_w); - video_timing_read_l = ISA_CYCLES(vid_timings->read_l); - video_timing_write_b = ISA_CYCLES(vid_timings->write_b); - video_timing_write_w = ISA_CYCLES(vid_timings->write_w); - video_timing_write_l = ISA_CYCLES(vid_timings->write_l); - } else if (vid_timings->type == VIDEO_PCI) { - video_timing_read_b = (int)(pci_timing * vid_timings->read_b); - video_timing_read_w = (int)(pci_timing * vid_timings->read_w); - video_timing_read_l = (int)(pci_timing * vid_timings->read_l); - video_timing_write_b = (int)(pci_timing * vid_timings->write_b); - video_timing_write_w = (int)(pci_timing * vid_timings->write_w); - video_timing_write_l = (int)(pci_timing * vid_timings->write_l); - } else if (vid_timings->type == VIDEO_AGP) { - video_timing_read_b = (int)(agp_timing * vid_timings->read_b); - video_timing_read_w = (int)(agp_timing * vid_timings->read_w); - video_timing_read_l = (int)(agp_timing * vid_timings->read_l); - video_timing_write_b = (int)(agp_timing * vid_timings->write_b); - video_timing_write_w = (int)(agp_timing * vid_timings->write_w); - video_timing_write_l = (int)(agp_timing * vid_timings->write_l); - } else { - video_timing_read_b = (int)(bus_timing * vid_timings->read_b); - video_timing_read_w = (int)(bus_timing * vid_timings->read_w); - video_timing_read_l = (int)(bus_timing * vid_timings->read_l); - video_timing_write_b = (int)(bus_timing * vid_timings->write_b); - video_timing_write_w = (int)(bus_timing * vid_timings->write_w); - video_timing_write_l = (int)(bus_timing * vid_timings->write_l); - } + for (i = 0; i < MONITORS_NUM; i++) { + monitor_vid_timings = monitors[i].mon_vid_timings; + if (!monitor_vid_timings) + continue; + vid_timing_read_b = &monitors[i].mon_video_timing_read_b; + vid_timing_read_l = &monitors[i].mon_video_timing_read_l; + vid_timing_read_w = &monitors[i].mon_video_timing_read_w; + vid_timing_write_b = &monitors[i].mon_video_timing_write_b; + vid_timing_write_l = &monitors[i].mon_video_timing_write_l; + vid_timing_write_w = &monitors[i].mon_video_timing_write_w; - if (cpu_16bitbus) { - video_timing_read_l = video_timing_read_w * 2; - video_timing_write_l = video_timing_write_w * 2; + if (monitor_vid_timings->type == VIDEO_ISA) { + *vid_timing_read_b = ISA_CYCLES(monitor_vid_timings->read_b); + *vid_timing_read_w = ISA_CYCLES(monitor_vid_timings->read_w); + *vid_timing_read_l = ISA_CYCLES(monitor_vid_timings->read_l); + *vid_timing_write_b = ISA_CYCLES(monitor_vid_timings->write_b); + *vid_timing_write_w = ISA_CYCLES(monitor_vid_timings->write_w); + *vid_timing_write_l = ISA_CYCLES(monitor_vid_timings->write_l); + } else if (monitor_vid_timings->type == VIDEO_PCI) { + *vid_timing_read_b = (int)(pci_timing * monitor_vid_timings->read_b); + *vid_timing_read_w = (int)(pci_timing * monitor_vid_timings->read_w); + *vid_timing_read_l = (int)(pci_timing * monitor_vid_timings->read_l); + *vid_timing_write_b = (int)(pci_timing * monitor_vid_timings->write_b); + *vid_timing_write_w = (int)(pci_timing * monitor_vid_timings->write_w); + *vid_timing_write_l = (int)(pci_timing * monitor_vid_timings->write_l); + } else if (monitor_vid_timings->type == VIDEO_AGP) { + *vid_timing_read_b = (int)(agp_timing * monitor_vid_timings->read_b); + *vid_timing_read_w = (int)(agp_timing * monitor_vid_timings->read_w); + *vid_timing_read_l = (int)(agp_timing * monitor_vid_timings->read_l); + *vid_timing_write_b = (int)(agp_timing * monitor_vid_timings->write_b); + *vid_timing_write_w = (int)(agp_timing * monitor_vid_timings->write_w); + *vid_timing_write_l = (int)(agp_timing * monitor_vid_timings->write_l); + } else { + *vid_timing_read_b = (int)(bus_timing * monitor_vid_timings->read_b); + *vid_timing_read_w = (int)(bus_timing * monitor_vid_timings->read_w); + *vid_timing_read_l = (int)(bus_timing * monitor_vid_timings->read_l); + *vid_timing_write_b = (int)(bus_timing * monitor_vid_timings->write_b); + *vid_timing_write_w = (int)(bus_timing * monitor_vid_timings->write_w); + *vid_timing_write_l = (int)(bus_timing * monitor_vid_timings->write_l); + } + + if (cpu_16bitbus) { + *vid_timing_read_l = *vid_timing_read_w * 2; + *vid_timing_write_l = *vid_timing_write_w * 2; + } } } @@ -762,7 +857,7 @@ hline(bitmap_t *b, int x1, int y, int x2, uint32_t col) { int x; - if (y < 0 || y >= buffer32->h) + if (y < 0 || y >= b->h) return; for (x = x1; x < x2; x++) @@ -820,6 +915,55 @@ create_bitmap(int x, int y) return(b); } +void +video_monitor_init(int index) +{ + memset(&monitors[index], 0, sizeof(monitor_t)); + monitors[index].mon_xsize = 640; + monitors[index].mon_ysize = 480; + monitors[index].mon_res_x = 640; + monitors[index].mon_res_y = 480; + monitors[index].mon_scrnsz_x = 640; + monitors[index].mon_scrnsz_y = 480; + monitors[index].mon_efscrnsz_y = 480; + monitors[index].mon_unscaled_size_x = 480; + monitors[index].mon_unscaled_size_y = 480; + monitors[index].mon_bpp = 8; + monitors[index].mon_changeframecount = 2; + monitors[index].target_buffer = create_bitmap(2048, 2048); + monitors[index].mon_blit_data_ptr = calloc(1, sizeof(struct blit_data_struct)); + monitors[index].mon_blit_data_ptr->wake_blit_thread = thread_create_event(); + monitors[index].mon_blit_data_ptr->blit_complete = thread_create_event(); + monitors[index].mon_blit_data_ptr->buffer_not_in_use = thread_create_event(); + monitors[index].mon_blit_data_ptr->thread_run = 1; + monitors[index].mon_blit_data_ptr->monitor_index = index; + monitors[index].mon_pal_lookup = calloc(sizeof(uint32_t), 256); + monitors[index].mon_cga_palette = calloc(1, sizeof(int)); + monitors[index].mon_force_resize = 1; + monitors[index].mon_vid_type = VIDEO_FLAG_TYPE_NONE; + atomic_init(&doresize_monitors[index], 0); + if (index >= 1) ui_init_monitor(index); + monitors[index].mon_blit_data_ptr->blit_thread = thread_create(blit_thread, monitors[index].mon_blit_data_ptr); +} + +void +video_monitor_close(int monitor_index) +{ + if (monitors[monitor_index].target_buffer == NULL) { return; } + monitors[monitor_index].mon_blit_data_ptr->thread_run = 0; + thread_set_event(monitors[monitor_index].mon_blit_data_ptr->wake_blit_thread); + thread_wait(monitors[monitor_index].mon_blit_data_ptr->blit_thread); + if (monitor_index >= 1) ui_deinit_monitor(monitor_index); + thread_destroy_event(monitors[monitor_index].mon_blit_data_ptr->buffer_not_in_use); + thread_destroy_event(monitors[monitor_index].mon_blit_data_ptr->blit_complete); + thread_destroy_event(monitors[monitor_index].mon_blit_data_ptr->wake_blit_thread); + free(monitors[monitor_index].mon_blit_data_ptr); + if (!monitors[monitor_index].mon_pal_lookup_static) free(monitors[monitor_index].mon_pal_lookup); + if (!monitors[monitor_index].mon_cga_palette_static) free(monitors[monitor_index].mon_cga_palette); + destroy_bitmap(monitors[monitor_index].target_buffer); + monitors[monitor_index].target_buffer = NULL; + memset(&monitors[monitor_index], 0, sizeof(monitor_t)); +} void video_init(void) @@ -832,9 +976,6 @@ video_init(void) (total[(c >> 1) & 1] << 16) | (total[(c >> 0) & 1] << 24); } - /* Account for overscan. */ - buffer32 = create_bitmap(2048, 2048); - for (c = 0; c < 64; c++) { cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; @@ -878,23 +1019,15 @@ video_init(void) for (c = 0; c < 65536; c++) video_16to32[c] = calc_16to32(c); - blit_data.wake_blit_thread = thread_create_event(); - blit_data.blit_complete = thread_create_event(); - blit_data.buffer_not_in_use = thread_create_event(); - thread_run = 1; - blit_data.blit_thread = thread_create(blit_thread, NULL); + memset(monitors, 0, sizeof(monitors)); + video_monitor_init(0); } void video_close(void) { - thread_run = 0; - thread_set_event(blit_data.wake_blit_thread); - thread_wait(blit_data.blit_thread); - thread_destroy_event(blit_data.buffer_not_in_use); - thread_destroy_event(blit_data.blit_complete); - thread_destroy_event(blit_data.wake_blit_thread); + video_monitor_close(0); free(video_16to32); free(video_15to32); @@ -902,8 +1035,6 @@ video_close(void) free(video_8togs); free(video_6to8); - destroy_bitmap(buffer32); - if (fontdatksc5601) { free(fontdatksc5601); fontdatksc5601 = NULL; @@ -915,18 +1046,29 @@ video_close(void) } } +uint8_t +video_force_resize_get_monitor(int monitor_index) +{ + return monitors[monitor_index].mon_force_resize; +} uint8_t video_force_resize_get(void) { - return video_force_resize; + return monitors[monitor_index_global].mon_force_resize; +} + +void +video_force_resize_set_monitor(uint8_t res, int monitor_index) +{ + monitors[monitor_index].mon_force_resize = res; } void video_force_resize_set(uint8_t res) { - video_force_resize = res; + monitors[monitor_index_global].mon_force_resize = res; } void diff --git a/src/win/win.c b/src/win/win.c index 382c58b70..7636d9f36 100644 --- a/src/win/win.c +++ b/src/win/win.c @@ -495,6 +495,9 @@ WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) return(1); } + extern int gfxcard_2; + gfxcard_2 = 0; + /* Create console window. */ if (force_debug) { CreateConsole(1); @@ -552,11 +555,12 @@ main_thread(void *param) Sleep(1); /* If needed, handle a screen resize. */ - if (!atomic_flag_test_and_set(&doresize) && !video_fullscreen && !is_quit) { + if (atomic_load(&doresize_monitors[0]) && !video_fullscreen && !is_quit) { if (vid_resize & 2) plat_resize(fixed_size_x, fixed_size_y); else plat_resize(scrnsz_x, scrnsz_y); + atomic_store(&doresize_monitors[0], 0); } } @@ -1189,7 +1193,7 @@ plat_setfullscreen(int on) video_fullscreen &= 1; video_force_resize_set(1); if (!(on & 1)) - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); win_mouse_init(); diff --git a/src/win/win_opengl.c b/src/win/win_opengl.c index b1dab78ca..8b8d39492 100644 --- a/src/win/win_opengl.c +++ b/src/win/win_opengl.c @@ -871,14 +871,14 @@ static void opengl_main(void* param) CoUninitialize(); } -static void opengl_blit(int x, int y, int w, int h) +static void opengl_blit(int x, int y, int w, int h, int monitor_index) { int row; if ((x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (thread == NULL) || - atomic_flag_test_and_set(&blit_info[write_pos].in_use)) + atomic_flag_test_and_set(&blit_info[write_pos].in_use) || monitor_index >= 1) { - video_blit_complete(); + video_blit_complete_monitor(monitor_index); return; } diff --git a/src/win/win_sdl.c b/src/win/win_sdl.c index cd4b26169..8bb0428c9 100644 --- a/src/win/win_sdl.c +++ b/src/win/win_sdl.c @@ -229,13 +229,13 @@ sdl_stretch(int *w, int *h, int *x, int *y) static void -sdl_blit(int x, int y, int w, int h) +sdl_blit(int x, int y, int w, int h, int monitor_index) { SDL_Rect r_src; int ret; - if (!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL)) { - video_blit_complete(); + if (!sdl_enabled || (x < 0) || (y < 0) || (w <= 0) || (h <= 0) || (w > 2048) || (h > 2048) || (buffer32 == NULL) || (sdl_render == NULL) || (sdl_tex == NULL) || monitor_index >= 1) { + video_blit_complete_monitor(monitor_index); return; } @@ -269,7 +269,7 @@ sdl_blit(int x, int y, int w, int h) static void -sdl_blit_ex(int x, int y, int w, int h) +sdl_blit_ex(int x, int y, int w, int h, int monitor_index) { SDL_Rect r_src; void *pixeldata; diff --git a/src/win/win_specify_dim.c b/src/win/win_specify_dim.c index 64a95cef4..f2d8a768d 100644 --- a/src/win/win_specify_dim.c +++ b/src/win/win_specify_dim.c @@ -28,6 +28,7 @@ #include <86box/86box.h> #include <86box/config.h> #include <86box/plat.h> +#include <86box/video.h> #include <86box/sound.h> #include <86box/win.h> @@ -133,7 +134,7 @@ SpecifyDimensionsDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM scrnsz_x = fixed_size_x; scrnsz_y = fixed_size_y; - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); GetWindowRect(hwndMain, &r); diff --git a/src/win/win_toolbar.c b/src/win/win_toolbar.c index e3480bc06..322038fda 100644 --- a/src/win/win_toolbar.c +++ b/src/win/win_toolbar.c @@ -8,6 +8,7 @@ #include <86box/plat.h> #include <86box/resource.h> #include <86box/ui.h> +#include <86box/video.h> #include <86box/win.h> HWND hwndRebar = NULL; diff --git a/src/win/win_ui.c b/src/win/win_ui.c index 1a9ad961a..3fc03e191 100644 --- a/src/win/win_ui.c +++ b/src/win/win_ui.c @@ -646,7 +646,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) scrnsz_x = unscaled_size_x; scrnsz_y = unscaled_size_y; - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); config_save(); break; @@ -745,7 +745,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) reset_screen_size(); device_force_redraw(); video_force_resize_set(1); - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); config_save(); break; @@ -760,7 +760,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) case IDM_VID_HIDPI: dpi_scale = !dpi_scale; CheckMenuItem(hmenu, IDM_VID_HIDPI, dpi_scale ? MF_CHECKED : MF_UNCHECKED); - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); config_save(); break; @@ -860,7 +860,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* Main Window. */ ResizeWindowByClientArea(hwndMain, temp_x, temp_y + (hide_status_bar ? 0 : sbar_height) + (hide_tool_bar ? 0 : tbar_height)); } else if (!user_resize) - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); break; case WM_WINDOWPOSCHANGED: @@ -909,13 +909,13 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) if (temp_x != scrnsz_x || temp_y != scrnsz_y) { scrnsz_x = temp_x; scrnsz_y = temp_y; - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); } } else { if (rect.right != scrnsz_x || rect.bottom != scrnsz_y) { scrnsz_x = rect.right; scrnsz_y = rect.bottom; - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); } } @@ -1092,7 +1092,7 @@ MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) /* If window is not resizable, then tell the main thread to resize it, as sometimes, moves can mess up the window size. */ if (!vid_resize) - atomic_flag_clear(&doresize); + atomic_store(&doresize_monitors[0], 1); break; } @@ -1580,3 +1580,6 @@ plat_mouse_capture(int on) mouse_capture = 0; } } + +void ui_init_monitor(int monitor_index) {} +void ui_deinit_monitor(int monitor_index) {} diff --git a/vcpkg.json b/vcpkg.json index 3583bb961..f3b639078 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -25,6 +25,7 @@ "network", "vulkan", "widgets", + "png", "zstd" ] },