]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
2420b10
authorToni Wilen <twilen@winuae.net>
Mon, 6 Aug 2012 17:51:10 +0000 (20:51 +0300)
committerToni Wilen <twilen@winuae.net>
Mon, 6 Aug 2012 17:51:10 +0000 (20:51 +0300)
18 files changed:
blitter.cpp
cfgfile.cpp
custom.cpp
drawing - Copy.cpp [new file with mode: 0644]
drawing.cpp
hardfile.cpp
include/filesys.h
include/inputdevice.h
include/options.h
inputdevice.cpp
od-win32/keyboard_win32.cpp
od-win32/resources/resource
od-win32/resources/winuae.rc
od-win32/rp.cpp
od-win32/win32.h
od-win32/win32_scaler.cpp
od-win32/win32gui.cpp
od-win32/winuaechangelog.txt

index 2e8d35c0539813179239b568bf2253c6d379ae77..7f7e02c32a8a3ab4af83297896432aaf7b805c30 100644 (file)
@@ -1444,12 +1444,14 @@ void maybe_blit (int hpos, int hack)
        if (savestate_state)
                return;
 
-       if (dmaen (DMA_BLITTER) && (currprefs.waiting_blits || currprefs.m68k_speed < 0)) {
-               while (bltstate != BLT_done && dmaen (DMA_BLITTER)) {
-                       x_do_cycles (8 * CYCLE_UNIT);
+       if (dmaen (DMA_BLITTER)) {
+               if (currprefs.waiting_blits == 1 || (currprefs.waiting_blits == 2 &&  blit_last_cycle >= blit_diag[0] && blit_dmacount == blit_diag[0]) || currprefs.m68k_speed < 0) {
+                       while (bltstate != BLT_done && dmaen (DMA_BLITTER)) {
+                               x_do_cycles (8 * CYCLE_UNIT);
+                       }
+                       if (bltstate == BLT_done)
+                               return;
                }
-               if (bltstate == BLT_done)
-                       return;
        }
 
        if (warned && dmaen (DMA_BLITTER) && blt_info.got_cycle) {
index 321e89c5af6d1a01fa9e6a83cb98135b6e0fc4d2..c5cdde0138f1317aaae00e4a18913621e589d63e 100644 (file)
@@ -188,6 +188,7 @@ static const TCHAR *cdmodes[] = { _T("disabled"), _T(""), _T("image"), _T("ioctl
 static const TCHAR *cdconmodes[] = { _T(""), _T("uae"), _T("ide"), _T("scsi"), _T("cdtv"), _T("cd32"), 0 };
 static const TCHAR *specialmonitors[] = { _T("none"), _T("autodetect"), _T("a2024"), _T("graffiti"), 0 };
 static const TCHAR *rtgtype[] = { _T("ZorroII"), _T("ZorroIII"), 0 };
+static const TCHAR *waitblits[] = { _T("false"), _T("true"), _T("noidleonly"), 0 };
 
 static const TCHAR *obsolete[] = {
        _T("accuracy"), _T("gfx_opengl"), _T("gfx_32bit_blits"), _T("32bit_blits"),
@@ -914,7 +915,7 @@ void cfgfile_save_options (struct zfile *f, struct uae_prefs *p, int type)
 #endif
 
        cfgfile_write_bool (f, _T("immediate_blits"), p->immediate_blits);
-       cfgfile_write_bool (f, _T("waiting_blits"), p->waiting_blits);
+       cfgfile_dwrite_str (f, _T("waiting_blits"), waitblits[p->waiting_blits]);
        cfgfile_write_bool (f, _T("ntsc"), p->ntscmode);
        cfgfile_write_bool (f, _T("genlock"), p->genlock);
        cfgfile_dwrite_str (f, _T("monitoremu"), specialmonitors[p->monitoremu]);
@@ -1182,9 +1183,14 @@ int cfgfile_strval (const TCHAR *option, const TCHAR *value, const TCHAR *name,
        if (val == -1) {
                if (more)
                        return 0;
-
-               write_log (_T("Unknown value ('%s') for option '%s'.\n"), value, option);
-               return -1;
+               if (!strcasecmp (value, _T("yes")) || !strcasecmp (value, _T("true"))) {
+                       val = 1;
+               } else if  (!strcasecmp (value, _T("no")) || !strcasecmp (value, _T("false"))) {
+                       val = 0;
+               } else {
+                       write_log (_T("Unknown value ('%s') for option '%s'.\n"), value, option);
+                       return -1;
+               }
        }
        *location = val;
        return 1;
@@ -2507,7 +2513,6 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH
                return 1;
 
        if (cfgfile_yesno (option, value, _T("immediate_blits"), &p->immediate_blits)
-               || cfgfile_yesno (option, value, _T("waiting_blits"), &p->waiting_blits)
                || cfgfile_yesno (option, value, _T("cd32cd"), &p->cs_cd32cd)
                || cfgfile_yesno (option, value, _T("cd32c2p"), &p->cs_cd32c2p)
                || cfgfile_yesno (option, value, _T("cd32nvram"), &p->cs_cd32nvram)
@@ -2603,6 +2608,7 @@ static int cfgfile_parse_hardware (struct uae_prefs *p, const TCHAR *option, TCH
                || cfgfile_strval (option, value, _T("collision_level"), &p->collision_level, collmode, 0)
                || cfgfile_strval (option, value, _T("parallel_matrix_emulation"), &p->parallel_matrix_emulation, epsonprinter, 0)
                || cfgfile_strval (option, value, _T("monitoremu"), &p->monitoremu, specialmonitors, 0)
+               || cfgfile_strval (option, value, _T("waiting_blits"), &p->waiting_blits, waitblits, 0)
                || cfgfile_strboolval (option, value, _T("comp_flushmode"), &p->comp_hardflush, flushmode, 0))
                return 1;
 
index 0b770e7ad7d0f62e5723ba1f616f7cdf402b632f..0b7bcc35b03d6d2f45121133fff35bc698c654b1 100644 (file)
@@ -306,6 +306,8 @@ enum copper_states {
        COP_skip1,
        COP_strobe_delay1,
        COP_strobe_delay2,
+       COP_strobe_delay1x,
+       COP_strobe_delay2x,
        COP_strobe_extra, // just to skip current cycle when CPU wrote to COPJMP
        COP_start_delay
 };
@@ -590,10 +592,10 @@ static void decide_diw (int hpos)
        */
 
        int hdiw = hpos >= maxhpos ? maxhpos * 2 + 1 : hpos * 2 + 2;
-       if (!(currprefs.chipset_mask & CSMASK_ECS_DENISE) && vpos <= get_equ_vblank_endline ()) {
+       if (!(currprefs.chipset_mask & CSMASK_ECS_DENISE) && vpos <= get_equ_vblank_endline ())
                hdiw = diw_hcounter;
-               hdiw &= 511;
-       }
+       /* always mask, bad programs may have set maxhpos = 256 */
+       hdiw &= 511;
        for (;;) {
                int lhdiw = hdiw;
                if (last_hdiw > lhdiw)
@@ -1354,17 +1356,17 @@ STATIC_INLINE void beginning_of_plane_block (int hpos, int fm)
                }
 #endif
 
-               update_denise (hpos);
-               maybe_first_bpl1dat (hpos);
-
+       update_denise (hpos);
+       maybe_first_bpl1dat (hpos);
+
+       bplcon1t2 = bplcon1t;
+       bplcon1t = bplcon1;
+       // writing to BPLCON1 1 cycle after BPL1DAT access will
+       // not (except first BPL1DAT write) affect the display
+       // until next display block
+       if (bplcon1_hpos != hpos || oleft < 0)
                bplcon1t2 = bplcon1t;
-               bplcon1t = bplcon1;
-               // writing to BPLCON1 1 cycle after BPL1DAT access will
-               // not (except first BPL1DAT write) affect the display
-               // until next display block
-               if (bplcon1_hpos != hpos || oleft < 0)
-                       bplcon1t2 = bplcon1t;
-               compute_toscr_delay (hpos, bplcon1t2);
+       compute_toscr_delay (hpos, bplcon1t2);
 }
 
 #ifdef SPEEDUP
@@ -3494,7 +3496,11 @@ static void COPJMP (int num, int vblank)
        cop_state.ignore_next = 0;
        if (!oldstrobe)
                cop_state.state_prev = cop_state.state;
-       cop_state.state = vblank ? COP_start_delay : (copper_access ? COP_strobe_delay1 : COP_strobe_extra);
+       if ((cop_state.state == COP_wait || cop_state.state == COP_stop) && !vblank) {
+               cop_state.state = COP_strobe_delay1x;
+       } else {
+               cop_state.state = vblank ? COP_start_delay : (copper_access ? COP_strobe_delay1 : COP_strobe_extra);
+       }
        cop_state.vpos = vpos;
        cop_state.hpos = current_hpos () & ~1;
        copper_enabled_thisline = 0;
@@ -3956,14 +3962,17 @@ static void BPL2MOD (int hpos, uae_u16 v)
  */
 static void BPLxDAT (int hpos, int num, uae_u16 v)
 {
-       decide_line (hpos);
-       decide_fetch (hpos);
+       // only BPL0DAT access can do anything visible
+       if (num == 0 && hpos >= 7) {
+               decide_line (hpos);
+               decide_fetch (hpos);
+       }
        bplxdat[num] = v;
-       if (num == 0) {
+       if (num == 0 && hpos >= 7) {
                bpl1dat_written = true;
                bpl1dat_written_at_least_once = true;
                if (thisline_decision.plfleft < 0) {
-                       thisline_decision.plfleft = hpos;
+                       thisline_decision.plfleft = hpos & ~3;
                        reset_bpl_vars ();
                        compute_delay_offset ();
                }
@@ -4494,7 +4503,7 @@ STATIC_INLINE int copper_cant_read2 (int hpos, int alloc)
 {
        if (hpos + 1 >= maxhpos) // first refresh slot
                return 1;
-       if ((hpos == maxhpos - 3) && (maxhpos & 1)) {
+       if ((hpos == maxhpos - 3) && (maxhpos & 1) && alloc >= 0) {
                if (alloc)
                        alloc_cycle (hpos, CYCLE_COPPER);
                return -1;
@@ -4619,12 +4628,14 @@ static void update_copper (int until_hpos)
                                continue;
                        cop_state.state = COP_skip1;
                        break;
+
                case COP_strobe_extra:
-                       // wait 1 copper cycle doing nothing
+                       // Wait 1 copper cycle doing nothing
                        cop_state.state = COP_strobe_delay1;
                        break;
                case COP_strobe_delay1:
-                       // first cycle after COPJMP is just like normal first read cycle
+                       // First cycle after COPJMP is just like normal first read cycle
+                       // Cycle is used and needs to be free.
                        if (copper_cant_read (old_hpos, 1))
                                continue;
                        cop_state.state = COP_strobe_delay2;
@@ -4636,22 +4647,46 @@ static void update_copper (int until_hpos)
                        cop_state.ip += 2;
                        break;
                case COP_strobe_delay2:
-                       // second cycle after COPJMP is like second read cycle except
-                       // there is 0x1FE as a target register
-                       // (following word is still read normally and tossed away)
+                       // Second cycle after COPJMP. This is the strange one.
+                       // This cycle does not need to be free
+                       // But it still gets allocated by copper if it is free = CPU and blitter can't use it.
+                       if (copper_cant_read (old_hpos, 1)) {
+                               alloc_cycle (old_hpos, CYCLE_COPPER);
+                               if (debug_dma)
+                                       record_dma (0x1fe, chipmem_wget_indirect (cop_state.ip), cop_state.ip, old_hpos, vpos, DMARECORD_COPPER);
+                       }
+                       cop_state.state = COP_read1;
+                       // Next cycle finally reads from new pointer
+                       if (cop_state.strobe == 1)
+                               cop_state.ip = cop1lc;
+                       else
+                               cop_state.ip = cop2lc;
+                       cop_state.strobe = 0;
+                       break;
+
+               case COP_strobe_delay1x:
+                       // First cycle after COPJMP and Copper was waiting. This is the buggy one.
+                       // Cycle can be free and copper won't allocate it.
+                       // If Blitter uses this cycle = Copper's address gets copied blitter DMA pointer..
+                       cop_state.state = COP_strobe_delay2x;
+                       break;
+               case COP_strobe_delay2x:
+                       // Second cycle fetches following word and tosses it away. Must be free cycle.
                        if (copper_cant_read (old_hpos, 1))
                                continue;
-                       cop_state.state = COP_read1;
                        alloc_cycle (old_hpos, CYCLE_COPPER);
                        if (debug_dma)
                                record_dma (0x1fe, chipmem_wget_indirect (cop_state.ip), cop_state.ip, old_hpos, vpos, DMARECORD_COPPER);
-                       // next cycle finally reads from new pointer
+                       cop_state.state = COP_read1;
+                       // Next cycle finally reads from new pointer
                        if (cop_state.strobe == 1)
                                cop_state.ip = cop1lc;
                        else
                                cop_state.ip = cop2lc;
                        cop_state.strobe = 0;
-                       break;
+               break;
+
+
                case COP_start_delay:
                        if (copper_cant_read (old_hpos, 1))
                                continue;
@@ -4709,10 +4744,9 @@ static void update_copper (int until_hpos)
                                test_copper_dangerous (reg);
                                if (! copper_enabled_thisline)
                                        goto out; // was "dangerous" register -> copper stopped
-                               if (cop_state.ignore_next) {
+
+                               if (cop_state.ignore_next)
                                        reg = 0x1fe;
-                                       cop_state.ignore_next = 0;
-                               }
 
                                cop_state.last_write = reg;
                                cop_state.last_write_hpos = old_hpos;
@@ -4742,9 +4776,10 @@ static void update_copper (int until_hpos)
 #endif
                                }
 #ifdef DEBUGGER
-                               if (debug_copper)
+                               if (debug_copper && !cop_state.ignore_next)
                                        record_copper (debugip - 4, old_hpos, vpos);
 #endif
+                               cop_state.ignore_next = 0;
                        }
                        break;
 
@@ -4764,8 +4799,12 @@ static void update_copper (int until_hpos)
                        incrementing vpos and setting c_hpos to 0.  Especially the various speedup
                        hacks really assume that vpos remains constant during one line.  Hence,
                        this hack: defer the entire decision until the next line if necessary.  */
-                       if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1))
+#endif
+#if 0
+                       if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1)) {
+                               write_log(L"*\n");
                                break;
+                       }
 #endif
                        cop_state.state = COP_wait;
 
@@ -4788,35 +4827,42 @@ static void update_copper (int until_hpos)
 
                        /* fall through */
                case COP_wait:
-                       if (copper_cant_read (old_hpos, 0))
-                               continue;
+                       {
+                               int ch_comp = c_hpos;
+                               if (ch_comp & 1)
+                                       ch_comp = 0;
+               
+                               if (copper_cant_read (old_hpos, 0))
+                                       continue;
 
-                       hp = c_hpos & (cop_state.saved_i2 & 0xFE);
-                       if (vp == cop_state.vcmp && hp < cop_state.hcmp)
-                               break;
 
-                       /* Now we know that the comparisons were successful.  We might still
-                       have to wait for the blitter though.  */
-                       if ((cop_state.saved_i2 & 0x8000) == 0) {
-                               decide_blitter (old_hpos);
-                               if (bltstate != BLT_done) {
-                                       /* We need to wait for the blitter.  */
-                                       cop_state.state = COP_bltwait;
-                                       copper_enabled_thisline = 0;
-                                       unset_special (SPCFLAG_COPPER);
-                                       goto out;
-                               } else {
-                                       if (debug_dma)
-                                               record_dma_event (DMA_EVENT_COPPERWAKE, old_hpos, vp);
+                               hp = ch_comp & (cop_state.saved_i2 & 0xFE);
+                               if (vp == cop_state.vcmp && hp < cop_state.hcmp)
+                                       break;
+
+                               /* Now we know that the comparisons were successful.  We might still
+                               have to wait for the blitter though.  */
+                               if ((cop_state.saved_i2 & 0x8000) == 0) {
+                                       decide_blitter (old_hpos);
+                                       if (bltstate != BLT_done) {
+                                               /* We need to wait for the blitter.  */
+                                               cop_state.state = COP_bltwait;
+                                               copper_enabled_thisline = 0;
+                                               unset_special (SPCFLAG_COPPER);
+                                               goto out;
+                                       } else {
+                                               if (debug_dma)
+                                                       record_dma_event (DMA_EVENT_COPPERWAKE, old_hpos, vp);
+                                       }
                                }
-                       }
 
-#ifdef DEBUGGER
-                       if (debug_copper)
-                               record_copper (cop_state.ip - 4, old_hpos, vpos);
-#endif
+       #ifdef DEBUGGER
+                               if (debug_copper)
+                                       record_copper (cop_state.ip - 4, old_hpos, vpos);
+       #endif
 
-                       cop_state.state = COP_read1;
+                               cop_state.state = COP_read1;
+                       }
                        break;
 
                case COP_skip1:
@@ -4825,6 +4871,7 @@ static void update_copper (int until_hpos)
 
                                if (c_hpos >= (maxhpos & ~1) || (c_hpos & 1))
                                        break;
+
                                if (copper_cant_read (old_hpos, 0))
                                        continue;
 
@@ -7796,6 +7843,7 @@ void check_prefs_changed_custom (void)
        if (inputdevice_config_change_test ()) 
                inputdevice_copyconfig (&changed_prefs, &currprefs);
        currprefs.immediate_blits = changed_prefs.immediate_blits;
+       currprefs.waiting_blits = changed_prefs.waiting_blits;
        currprefs.collision_level = changed_prefs.collision_level;
 
        currprefs.cs_ciaatod = changed_prefs.cs_ciaatod;
diff --git a/drawing - Copy.cpp b/drawing - Copy.cpp
new file mode 100644 (file)
index 0000000..4c2def4
--- /dev/null
@@ -0,0 +1,3119 @@
+//#define XLINECHECK
+
+/*
+* UAE - The Un*x Amiga Emulator
+*
+* Screen drawing functions
+*
+* Copyright 1995-2000 Bernd Schmidt
+* Copyright 1995 Alessandro Bissacco
+* Copyright 2000-2008 Toni Wilen
+*/
+
+/* There are a couple of concepts of "coordinates" in this file.
+- DIW coordinates
+- DDF coordinates (essentially cycles, resolution lower than lores by a factor of 2)
+- Pixel coordinates
+* in the Amiga's resolution as determined by BPLCON0 ("Amiga coordinates")
+* in the window resolution as determined by the preferences ("window coordinates").
+* in the window resolution, and with the origin being the topmost left corner of
+the window ("native coordinates")
+One note about window coordinates.  The visible area depends on the width of the
+window, and the centering code.  The first visible horizontal window coordinate is
+often _not_ 0, but the value of VISIBLE_LEFT_BORDER instead.
+
+One important thing to remember: DIW coordinates are in the lowest possible
+resolution.
+
+To prevent extremely bad things (think pixels cut in half by window borders) from
+happening, all ports should restrict window widths to be multiples of 16 pixels.  */
+
+#include "sysconfig.h"
+#include "sysdeps.h"
+
+#include <ctype.h>
+#include <assert.h>
+
+#include "options.h"
+#include "threaddep/thread.h"
+#include "uae.h"
+#include "memory.h"
+#include "custom.h"
+#include "newcpu.h"
+#include "xwin.h"
+#include "autoconf.h"
+#include "gui.h"
+#include "picasso96.h"
+#include "drawing.h"
+#include "savestate.h"
+#include "statusline.h"
+#include "inputdevice.h"
+#include "debug.h"
+
+extern bool emulate_specialmonitors (struct vidbuffer*, struct vidbuffer*);
+
+extern int sprite_buffer_res;
+int lores_factor, lores_shift;
+
+int debug_bpl_mask = 0xff, debug_bpl_mask_one;
+
+static void lores_reset (void)
+{
+       lores_factor = currprefs.gfx_resolution ? 2 : 1;
+       lores_shift = currprefs.gfx_resolution;
+       if (doublescan > 0) {
+               if (lores_shift < 2)
+                       lores_shift++;
+               lores_factor = 2;
+       }
+       sprite_buffer_res = currprefs.gfx_resolution;
+       if (doublescan > 0 && sprite_buffer_res < RES_SUPERHIRES)
+               sprite_buffer_res++;
+}
+
+bool aga_mode; /* mirror of chipset_mask & CSMASK_AGA */
+bool direct_rgb;
+
+/* The shift factor to apply when converting between Amiga coordinates and window
+coordinates.  Zero if the resolution is the same, positive if window coordinates
+have a higher resolution (i.e. we're stretching the image), negative if window
+coordinates have a lower resolution (i.e. we're shrinking the image).  */
+static int res_shift;
+
+static int linedbl, linedbld;
+
+int interlace_seen = 0;
+#define AUTO_LORES_FRAMES 10
+static int can_use_lores = 0, frame_res, frame_res_lace, last_max_ypos;
+static uae_u16 bplcon0_store, bplcon3_store;
+
+/* Lookup tables for dual playfields.  The dblpf_*1 versions are for the case
+that playfield 1 has the priority, dbplpf_*2 are used if playfield 2 has
+priority.  If we need an array for non-dual playfield mode, it has no number.  */
+/* The dbplpf_ms? arrays contain a shift value.  plf_spritemask is initialized
+to contain two 16 bit words, with the appropriate mask if pf1 is in the
+foreground being at bit offset 0, the one used if pf2 is in front being at
+offset 16.  */
+
+static int dblpf_ms1[256], dblpf_ms2[256], dblpf_ms[256];
+static int dblpf_ind1[256], dblpf_ind2[256];
+
+static int dblpf_2nd1[256], dblpf_2nd2[256];
+
+static const int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 };
+
+static int sprite_offs[256];
+
+static uae_u32 clxtab[256];
+
+/* Video buffer description structure. Filled in by the graphics system
+* dependent code. */
+
+struct vidbuf_description gfxvidinfo;
+
+/* OCS/ECS color lookup table. */
+xcolnr xcolors[4096];
+
+struct spritepixelsbuf {
+       uae_u8 attach;
+       uae_u8 stdata;
+       uae_u16 data;
+};
+static struct spritepixelsbuf spritepixels[MAX_PIXELS_PER_LINE];
+static int sprite_first_x, sprite_last_x;
+
+#ifdef AGA
+/* AGA mode color lookup tables */
+unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256];
+static int dblpf_ind1_aga[256], dblpf_ind2_aga[256];
+#else
+static uae_u8 spriteagadpfpixels[1];
+static int dblpf_ind1_aga[1], dblpf_ind2_aga[1];
+#endif
+int xredcolor_s, xredcolor_b, xredcolor_m;
+int xgreencolor_s, xgreencolor_b, xgreencolor_m;
+int xbluecolor_s, xbluecolor_b, xbluecolor_m;
+
+struct color_entry colors_for_drawing;
+
+/* The size of these arrays is pretty arbitrary; it was chosen to be "more
+than enough".  The coordinates used for indexing into these arrays are
+almost, but not quite, Amiga coordinates (there's a constant offset).  */
+union {
+       /* Let's try to align this thing. */
+       double uupzuq;
+       long int cruxmedo;
+       uae_u8 apixels[MAX_PIXELS_PER_LINE * 2];
+       uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / sizeof (uae_u16)];
+       uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / sizeof (uae_u32)];
+} pixdata;
+
+#ifdef OS_WITHOUT_MEMORY_MANAGEMENT
+uae_u16 *spixels;
+#else
+uae_u16 spixels[2 * MAX_SPR_PIXELS];
+#endif
+
+/* Eight bits for every pixel.  */
+union sps_union spixstate;
+
+static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2];
+static uae_u8 *real_bplpt[8];
+
+static uae_u8 all_ones[MAX_PIXELS_PER_LINE];
+static uae_u8 all_zeros[MAX_PIXELS_PER_LINE];
+
+uae_u8 *xlinebuffer;
+
+static int *amiga2aspect_line_map, *native2amiga_line_map;
+static uae_u8 *row_map[MAX_VIDHEIGHT + 1];
+static uae_u8 row_tmp[MAX_PIXELS_PER_LINE * 32 / 8];
+static int max_drawn_amiga_line;
+
+/* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham */
+typedef void (*line_draw_func)(int, int, bool);
+
+#define LINE_UNDECIDED 1
+#define LINE_DECIDED 2
+#define LINE_DECIDED_DOUBLE 3
+#define LINE_AS_PREVIOUS 4
+#define LINE_BLACK 5
+#define LINE_REMEMBERED_AS_BLACK 6
+#define LINE_DONE 7
+#define LINE_DONE_AS_PREVIOUS 8
+#define LINE_REMEMBERED_AS_PREVIOUS 9
+
+static uae_u8 linestate[(MAXVPOS + 2) * 2 + 1];
+
+uae_u8 line_data[(MAXVPOS + 2) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
+
+/* Centering variables.  */
+static int min_diwstart, max_diwstop;
+/* The visible window: VISIBLE_LEFT_BORDER contains the left border of the visible
+area, VISIBLE_RIGHT_BORDER the right border.  These are in window coordinates.  */
+int visible_left_border, visible_right_border;
+/* Pixels outside of visible_start and visible_stop are always black */
+static int visible_left_start, visible_right_stop;
+static int visible_top_start, visible_bottom_stop;
+
+static int linetoscr_x_adjust_bytes;
+static int thisframe_y_adjust;
+static int thisframe_y_adjust_real, max_ypos_thisframe, min_ypos_for_screen;
+static int extra_y_adjust;
+int thisframe_first_drawn_line, thisframe_last_drawn_line;
+
+/* A frame counter that forces a redraw after at least one skipped frame in
+interlace mode.  */
+static int last_redraw_point;
+
+#define MAX_STOP 30000
+static int first_drawn_line, last_drawn_line;
+static int first_block_line, last_block_line;
+
+#define NO_BLOCK -3
+
+/* These are generated by the drawing code from the line_decisions array for
+each line that needs to be drawn.  These are basically extracted out of
+bit fields in the hardware registers.  */
+static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt, ecsshres, issprites;
+static int bplres;
+static int plf1pri, plf2pri, bplxor;
+static uae_u32 plf_sprite_mask;
+static int sbasecol[2] = { 16, 16 };
+static bool brdsprt, brdblank, brdblank_changed;
+static int hposblank;
+
+bool picasso_requested_on;
+bool picasso_on;
+
+uae_sem_t gui_sem;
+int inhibit_frame;
+
+int framecnt = 0;
+static int frame_redraw_necessary;
+static int picasso_redraw_necessary;
+
+#ifdef XLINECHECK
+static void xlinecheck (unsigned int start, unsigned int end)
+{
+       unsigned int xstart = (unsigned int)xlinebuffer + start * gfxvidinfo.drawbuffer.pixbytes;
+       unsigned int xend = (unsigned int)xlinebuffer + end * gfxvidinfo.drawbuffer.pixbytes;
+       unsigned int end1 = (unsigned int)gfxvidinfo.drawbuffer.bufmem + gfxvidinfo.drawbuffer.rowbytes * gfxvidinfo.drawbuffer.height;
+       int min = linetoscr_x_adjust_bytes / gfxvidinfo.drawbuffer.pixbytes;
+       int ok = 1;
+
+       if (xstart >= gfxvidinfo.drawbuffer.emergmem && xstart < gfxvidinfo.drawbuffer.emergmem + 4096 * gfxvidinfo.drawbuffer.pixbytes &&
+               xend >= gfxvidinfo.drawbuffer.emergmem && xend < gfxvidinfo.drawbuffer.emergmem + 4096 * gfxvidinfo.drawbuffer.pixbytes)
+               return;
+
+       if (xstart < (unsigned int)gfxvidinfo.drawbuffer.bufmem || xend < (unsigned int)gfxvidinfo.drawbuffer.bufmem)
+               ok = 0;
+       if (xend > end1 || xstart >= end1)
+               ok = 0;
+       xstart -= (unsigned int)gfxvidinfo.drawbuffer.bufmem;
+       xend -= (unsigned int)gfxvidinfo.drawbuffer.bufmem;
+       if ((xstart % gfxvidinfo.drawbuffer.rowbytes) >= gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes)
+               ok = 0;
+       if ((xend % gfxvidinfo.drawbuffer.rowbytes) >= gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes)
+               ok = 0;
+       if (xstart >= xend)
+               ok = 0;
+       if (xend - xstart > gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes)
+               ok = 0;
+
+       if (!ok) {
+               write_log (_T("*** %d-%d (%dx%dx%d %d) %p\n"),
+                       start - min, end - min, gfxvidinfo.drawbuffer.width, gfxvidinfo.drawbuffer.height,
+                       gfxvidinfo.drawbuffer.pixbytes, gfxvidinfo.drawbuffer.rowbytes,
+                       xlinebuffer);
+       }
+}
+#else
+#define xlinecheck
+#endif
+
+
+STATIC_INLINE void count_frame (void)
+{
+       framecnt++;
+       if (framecnt >= currprefs.gfx_framerate)
+               framecnt = 0;
+       if (inhibit_frame)
+               framecnt = 1;
+}
+
+STATIC_INLINE int xshift (int x, int shift)
+{
+       if (shift < 0)
+               return x >> (-shift);
+       else
+               return x << shift;
+}
+
+int coord_native_to_amiga_x (int x)
+{
+       x += visible_left_border;
+       x = xshift (x, 1 - lores_shift);
+       return x + 2 * DISPLAY_LEFT_SHIFT - 2 * DIW_DDF_OFFSET;
+}
+
+int coord_native_to_amiga_y (int y)
+{
+       return native2amiga_line_map[y] + thisframe_y_adjust - minfirstline;
+}
+
+STATIC_INLINE int res_shift_from_window (int x)
+{
+       if (res_shift >= 0)
+               return x >> res_shift;
+       return x << -res_shift;
+}
+
+STATIC_INLINE int res_shift_from_amiga (int x)
+{
+       if (res_shift >= 0)
+               return x >> res_shift;
+       return x << -res_shift;
+}
+
+void notice_screen_contents_lost (void)
+{
+       picasso_redraw_necessary = 1;
+       frame_redraw_necessary = 2;
+}
+
+bool isnativevidbuf (void)
+{
+       if (gfxvidinfo.outbuffer == &gfxvidinfo.drawbuffer)
+               return true;
+       return gfxvidinfo.outbuffer->nativepositioning;
+}
+
+extern int plffirstline_total, plflastline_total;
+extern int first_planes_vpos, last_planes_vpos;
+extern int diwfirstword_total, diwlastword_total;
+extern int ddffirstword_total, ddflastword_total;
+extern int firstword_bplcon1;
+extern int lof_store;
+
+#define MIN_DISPLAY_W 256
+#define MIN_DISPLAY_H 192
+#define MAX_DISPLAY_W 362
+#define MAX_DISPLAY_H 283
+
+static int gclow, gcloh, gclox, gcloy;
+
+void get_custom_topedge (int *x, int *y)
+{
+       if (isnativevidbuf ()) {
+               *x = visible_left_border + (DISPLAY_LEFT_SHIFT << currprefs.gfx_resolution);
+               *y = minfirstline << currprefs.gfx_vresolution;
+       } else {
+               *x = 0;
+               *y = 0;
+       }
+}
+
+static void reset_custom_limits (void)
+{
+       gclow = gcloh = gclox = gcloy = 0;
+}
+
+void set_custom_limits (int w, int h, int dx, int dy)
+{
+       int vls = visible_left_start;
+       int vrs = visible_right_stop;
+       int vts = visible_top_start;
+       int vbs = visible_bottom_stop;
+
+       if (w <= 0 || dx < 0) {
+               visible_left_start = 0;
+               visible_right_stop = MAX_STOP;
+       } else {
+               visible_left_start = visible_left_border + dx;
+               visible_right_stop = visible_left_start + w;
+       }
+       if (h <= 0 || dy < 0) {
+               visible_top_start = 0;
+               visible_bottom_stop = MAX_STOP;
+       } else {
+               visible_top_start = min_ypos_for_screen + dy;
+               visible_bottom_stop = visible_top_start + h;
+       }
+       if (vls != visible_left_start || vrs != visible_right_stop ||
+               vts != visible_top_start || vbs != visible_bottom_stop)
+               notice_screen_contents_lost ();
+}
+
+int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy)
+{
+       int w, h, dx, dy, y1, y2, dbl1, dbl2;
+       int ret = 0;
+
+       if (!pw || !ph || !pdx || !pdy) {
+               reset_custom_limits ();
+               return 0;
+       }
+
+       if (!isnativevidbuf ()) {
+               *pw = gfxvidinfo.outbuffer->outwidth;
+               *ph = gfxvidinfo.outbuffer->outheight;
+               *pdx = 0;
+               *pdy = 0;
+               return 1;
+       }
+
+       *pw = gclow;
+       *ph = gcloh;
+       *pdx = gclox;
+       *pdy = gcloy;
+
+       if (gclow > 0 && gcloh > 0)
+               ret = -1;
+
+       if (interlace_seen) {
+               // interlace = only use long frames
+               if (!lof_store)
+                       return ret;
+               /* program may have set last visible line as last possible line (CD32 boot screen) */
+               if (last_planes_vpos < maxvpos)
+                       last_planes_vpos++;
+               if (plflastline_total < maxvpos)
+                       plflastline_total++;
+       }
+
+       if (plflastline_total < 4)
+               plflastline_total = last_planes_vpos;
+
+       ddffirstword_total = coord_hw_to_window_x (ddffirstword_total * 2 + DIW_DDF_OFFSET);
+       ddflastword_total = coord_hw_to_window_x (ddflastword_total * 2 + DIW_DDF_OFFSET);
+
+       if (doublescan <= 0 && !programmedmode) {
+               int min = coord_diw_to_window_x (92);
+               int max = coord_diw_to_window_x (460);
+               if (diwfirstword_total < min)
+                       diwfirstword_total = min;
+               if (diwlastword_total > max)
+                       diwlastword_total = max;
+               if (ddffirstword_total < min)
+                       ddffirstword_total = min;
+               if (ddflastword_total > max)
+                       ddflastword_total = max;
+               if (0 && !(currprefs.chipset_mask & CSMASK_AGA)) {
+                       if (ddffirstword_total > diwfirstword_total)
+                               diwfirstword_total = ddffirstword_total;
+                       if (ddflastword_total < diwlastword_total)
+                               diwlastword_total = ddflastword_total;
+               }
+       }
+
+       w = diwlastword_total - diwfirstword_total;
+       dx = diwfirstword_total - visible_left_border;
+
+       y2 = plflastline_total;
+       if (y2 > last_planes_vpos)
+               y2 = last_planes_vpos;
+       y1 = plffirstline_total;
+       if (first_planes_vpos > y1)
+               y1 = first_planes_vpos;
+       if (minfirstline > y1)
+               y1 = minfirstline;
+
+       dbl2 = dbl1 = currprefs.gfx_vresolution;
+       if (doublescan > 0 && interlace_seen <= 0) {
+               dbl1--;
+               dbl2--;
+       }
+
+       h = y2 - y1;
+       dy = y1 - minfirstline;
+
+       if (first_planes_vpos == 0) {
+               // no planes enabled during frame
+               if (ret < 0)
+                       return 1;
+               h = currprefs.ntscmode ? 200 : 240;
+               w = 320 << currprefs.gfx_resolution;
+               dy = 36 / 2;
+               dx = 58;
+       }
+
+       if (dx < 0)
+               dx = 0;
+
+       dy = xshift (dy, dbl2);
+       h = xshift (h, dbl1);
+
+       if (w == 0 || h == 0)
+               return 0;
+
+       if (doublescan <= 0 && !programmedmode) {
+               if ((w >> currprefs.gfx_resolution) < MIN_DISPLAY_W) {
+                       dx += (w - (MIN_DISPLAY_W << currprefs.gfx_resolution)) / 2;
+                       w = MIN_DISPLAY_W << currprefs.gfx_resolution;
+               }
+               if ((h >> dbl1) < MIN_DISPLAY_H) {
+                       dy += (h - (MIN_DISPLAY_H << dbl1)) / 2;
+                       h = MIN_DISPLAY_H << dbl1;
+               }
+               if ((w >> currprefs.gfx_resolution) > MAX_DISPLAY_W) {
+                       dx += (w - (MAX_DISPLAY_W << currprefs.gfx_resolution)) / 2;
+                       w = MAX_DISPLAY_W << currprefs.gfx_resolution;
+               }
+               if ((h >> dbl1) > MAX_DISPLAY_H) {
+                       dy += (h - (MAX_DISPLAY_H << dbl1)) / 2;
+                       h = MAX_DISPLAY_H << dbl1;
+               }
+       }
+
+       if (gclow == w && gcloh == h && gclox == dx && gcloy == dy)
+               return ret;
+
+       if (w <= 0 || h <= 0 || dx < 0 || dy < 0)
+               return ret;
+       if (doublescan <= 0 && !programmedmode) {
+               if (dx > gfxvidinfo.outbuffer->inwidth / 3)
+                       return ret;
+               if (dy > gfxvidinfo.outbuffer->inheight / 3)
+                       return ret;
+       }
+
+       gclow = w;
+       gcloh = h;
+       gclox = dx;
+       gcloy = dy;
+       *pw = w;
+       *ph = h;
+       *pdx = dx;
+       *pdy = dy;
+#if 1
+       write_log (_T("Display Size: %dx%d Offset: %dx%d\n"), w, h, dx, dy);
+       write_log (_T("First: %d Last: %d MinV: %d MaxV: %d Min: %d\n"),
+               plffirstline_total, plflastline_total,
+               first_planes_vpos, last_planes_vpos, minfirstline);
+#endif
+       return 1;
+}
+
+void get_custom_mouse_limits (int *pw, int *ph, int *pdx, int *pdy, int dbl)
+{
+       int delay1, delay2;
+       int w, h, dx, dy, dbl1, dbl2, y1, y2;
+
+       w = diwlastword_total - diwfirstword_total;
+       dx = diwfirstword_total - visible_left_border;
+
+       y2 = plflastline_total;
+       if (y2 > last_planes_vpos)
+               y2 = last_planes_vpos;
+       y1 = plffirstline_total;
+       if (first_planes_vpos > y1)
+               y1 = first_planes_vpos;
+       if (minfirstline > y1)
+               y1 = minfirstline;
+
+       h = y2 - y1;
+       dy = y1 - minfirstline;
+
+       if (*pw > 0)
+               w = *pw;
+
+       w = xshift (w, res_shift);
+
+       if (*ph > 0)
+               h = *ph;
+
+       delay1 = (firstword_bplcon1 & 0x0f) | ((firstword_bplcon1 & 0x0c00) >> 6);
+       delay2 = ((firstword_bplcon1 >> 4) & 0x0f) | (((firstword_bplcon1 >> 4) & 0x0c00) >> 6);
+//     if (delay1 == delay2)
+//             dx += delay1;
+
+       dx = xshift (dx, res_shift);
+
+       dbl2 = dbl1 = currprefs.gfx_vresolution;
+       if ((doublescan > 0 || interlace_seen > 0) && !dbl) {
+               dbl1--;
+               dbl2--;
+       }
+       if (interlace_seen > 0)
+               dbl2++;
+       if (interlace_seen <= 0 && dbl)
+               dbl2--;
+       h = xshift (h, dbl1);
+       dy = xshift (dy, dbl2);
+
+       if (w < 1)
+               w = 1;
+       if (h < 1)
+               h = 1;
+       if (dx < 0)
+               dx = 0;
+       if (dy < 0)
+               dy = 0;
+       *pw = w; *ph = h;
+       *pdx = dx; *pdy = dy;
+}
+
+static struct decision *dp_for_drawing;
+static struct draw_info *dip_for_drawing;
+
+/* Record DIW of the current line for use by centering code.  */
+void record_diw_line (int plfstrt, int first, int last)
+{
+       if (last > max_diwstop)
+               max_diwstop = last;
+       if (first < min_diwstart) {
+               min_diwstart = first;
+               /*
+               if (plfstrt * 2 > min_diwstart)
+               min_diwstart = plfstrt * 2;
+               */
+       }
+}
+
+/*
+* Screen update macros/functions
+*/
+
+/* The important positions in the line: where do we start drawing the left border,
+where do we start drawing the playfield, where do we start drawing the right border.
+All of these are forced into the visible window (VISIBLE_LEFT_BORDER .. VISIBLE_RIGHT_BORDER).
+PLAYFIELD_START and PLAYFIELD_END are in window coordinates.  */
+static int playfield_start, playfield_end;
+static int real_playfield_start, real_playfield_end;
+static int linetoscr_diw_start, linetoscr_diw_end;
+static int native_ddf_left, native_ddf_right;
+
+static int pixels_offset;
+static int src_pixel, ham_src_pixel;
+/* How many pixels in window coordinates which are to the left of the left border.  */
+static int unpainted;
+static int seen_sprites;
+
+/* Initialize the variables necessary for drawing a line.
+* This involves setting up start/stop positions and display window
+* borders.  */
+static void pfield_init_linetoscr (void)
+{
+       /* First, get data fetch start/stop in DIW coordinates.  */
+       int ddf_left = dp_for_drawing->plfleft * 2 + DIW_DDF_OFFSET;
+       int ddf_right = dp_for_drawing->plfright * 2 + DIW_DDF_OFFSET;
+
+       /* Compute datafetch start/stop in pixels; native display coordinates.  */
+       native_ddf_left = coord_hw_to_window_x (ddf_left);
+       native_ddf_right = coord_hw_to_window_x (ddf_right);
+
+       linetoscr_diw_start = dp_for_drawing->diwfirstword;
+       linetoscr_diw_end = dp_for_drawing->diwlastword;
+
+       res_shift = lores_shift - bplres;
+
+       if (dip_for_drawing->nr_sprites == 0) {
+               if (linetoscr_diw_start < native_ddf_left)
+                       linetoscr_diw_start = native_ddf_left;
+               if (linetoscr_diw_end > native_ddf_right)
+                       linetoscr_diw_end = native_ddf_right;
+       }
+
+       /* Perverse cases happen. */
+       if (linetoscr_diw_end < linetoscr_diw_start)
+               linetoscr_diw_end = linetoscr_diw_start;
+
+       playfield_start = linetoscr_diw_start;
+       playfield_end = linetoscr_diw_end;
+
+       unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start;
+       ham_src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left);
+       unpainted = res_shift_from_window (unpainted);
+
+       if (playfield_start < visible_left_border)
+               playfield_start = visible_left_border;
+       if (playfield_start > visible_right_border)
+               playfield_start = visible_right_border;
+       if (playfield_end < visible_left_border)
+               playfield_end = visible_left_border;
+       if (playfield_end > visible_right_border)
+               playfield_end = visible_right_border;
+
+       real_playfield_end = playfield_end;
+       real_playfield_start = playfield_start;
+#ifdef AGA
+       if (brdsprt && dip_for_drawing->nr_sprites) {
+               int min = visible_right_border, max = visible_left_border, i;
+               for (i = 0; i < dip_for_drawing->nr_sprites; i++) {
+                       int x;
+                       x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].pos;
+                       if (x < min)
+                               min = x;
+                       x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].max;
+                       if (x > max)
+                               max = x;
+               }
+               min = coord_hw_to_window_x (min >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift);
+               max = coord_hw_to_window_x (max >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift);
+               if (min < playfield_start)
+                       playfield_start = min;
+               if (playfield_start < visible_left_border)
+                       playfield_start = visible_left_border;
+               if (max > playfield_end)
+                       playfield_end = max;
+               if (playfield_end > visible_right_border)
+                       playfield_end = visible_right_border;
+       }
+#endif
+
+       if (sprite_first_x < sprite_last_x) {
+               if (sprite_first_x < 0)
+                       sprite_first_x = 0;
+               if (sprite_last_x >= MAX_PIXELS_PER_LINE - 1)
+                       sprite_last_x = MAX_PIXELS_PER_LINE - 2;
+               if (sprite_first_x < sprite_last_x)
+                       memset (spritepixels + sprite_first_x, 0, sizeof (struct spritepixelsbuf) * (sprite_last_x - sprite_first_x + 1));
+       }
+       sprite_last_x = 0;
+       sprite_first_x = MAX_PIXELS_PER_LINE - 1;
+
+       /* Now, compute some offsets.  */
+       ddf_left -= DISPLAY_LEFT_SHIFT;
+       pixels_offset = MAX_PIXELS_PER_LINE - (ddf_left << bplres);
+       ddf_left <<= bplres;
+       src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (playfield_start - native_ddf_left);
+
+       seen_sprites = 0;
+       if (dip_for_drawing->nr_sprites == 0)
+               return;
+       seen_sprites = 1;
+       /* Must clear parts of apixels.  */
+       if (linetoscr_diw_start < native_ddf_left) {
+               int size = res_shift_from_window (native_ddf_left - linetoscr_diw_start);
+               linetoscr_diw_start = native_ddf_left;
+               memset (pixdata.apixels + MAX_PIXELS_PER_LINE - size, 0, size);
+       }
+       if (linetoscr_diw_end > native_ddf_right) {
+               int pos = res_shift_from_window (native_ddf_right - native_ddf_left);
+               int size = res_shift_from_window (linetoscr_diw_end - native_ddf_right);
+               linetoscr_diw_start = native_ddf_left;
+               memset (pixdata.apixels + MAX_PIXELS_PER_LINE + pos, 0, size);
+       }
+}
+
+STATIC_INLINE uae_u16 merge_2pixel16 (uae_u16 p1, uae_u16 p2)
+{
+       uae_u16 v = ((((p1 >> xredcolor_s) & xredcolor_m) + ((p2 >> xredcolor_s) & xredcolor_m)) / 2) << xredcolor_s;
+       v |= ((((p1 >> xbluecolor_s) & xbluecolor_m) + ((p2 >> xbluecolor_s) & xbluecolor_m)) / 2) << xbluecolor_s;
+       v |= ((((p1 >> xgreencolor_s) & xgreencolor_m) + ((p2 >> xgreencolor_s) & xgreencolor_m)) / 2) << xgreencolor_s;
+       return v;
+}
+STATIC_INLINE uae_u32 merge_2pixel32 (uae_u32 p1, uae_u32 p2)
+{
+       uae_u32 v = ((((p1 >> 16) & 0xff) + ((p2 >> 16) & 0xff)) / 2) << 16;
+       v |= ((((p1 >> 8) & 0xff) + ((p2 >> 8) & 0xff)) / 2) << 8;
+       v |= ((((p1 >> 0) & 0xff) + ((p2 >> 0) & 0xff)) / 2) << 0;
+       return v;
+}
+
+STATIC_INLINE xcolnr getbgc (bool blank)
+{
+#if 0
+       if (blank)
+               return xcolors[0x088];
+       else if (hposblank == 1)
+               return xcolors[0xf00];
+       else if (hposblank == 2)
+               return xcolors[0x0f0];
+       else if (hposblank == 3)
+               return xcolors[0x00f];
+       else if (brdblank)
+               return xcolors[0x880];
+       return xcolors[0xf0f];
+#endif
+       return (blank || brdblank || hposblank) ? 0 : colors_for_drawing.acolors[0];
+}
+
+STATIC_INLINE void fill_line_16 (uae_u8 *buf, int start, int stop, bool blank)
+{
+       uae_u16 *b = (uae_u16 *)buf;
+       unsigned int i;
+       unsigned int rem = 0;
+       xcolnr col = getbgc (blank);
+       if (((long)&b[start]) & 1)
+               b[start++] = (uae_u16) col;
+       if (start >= stop)
+               return;
+       if (((long)&b[stop]) & 1) {
+               rem++;
+               stop--;
+       }
+       for (i = start; i < stop; i += 2) {
+               uae_u32 *b2 = (uae_u32 *)&b[i];
+               *b2 = col;
+       }
+       if (rem)
+               b[stop] = (uae_u16)col;
+}
+
+STATIC_INLINE void fill_line_32 (uae_u8 *buf, int start, int stop, bool blank)
+{
+       uae_u32 *b = (uae_u32 *)buf;
+       unsigned int i;
+       xcolnr col = getbgc (blank);
+       for (i = start; i < stop; i++)
+               b[i] = col;
+}
+static void pfield_do_fill_line2 (int start, int stop, bool blank)
+{
+       switch (gfxvidinfo.drawbuffer.pixbytes) {
+       case 2: fill_line_16 (xlinebuffer, start, stop, blank); break;
+       case 4: fill_line_32 (xlinebuffer, start, stop, blank); break;
+       }
+}
+static void pfield_do_fill_line (int start, int stop, bool blank)
+{
+       xlinecheck(start, stop);
+       if (!blank) {
+               if (start < visible_left_start) {
+                       pfield_do_fill_line2 (start, visible_left_start, true);
+                       start = visible_left_start;
+               }
+               if (stop > visible_right_stop) {
+                       pfield_do_fill_line2 (start, visible_right_stop, false);
+                       blank = true;
+                       start = visible_right_stop;
+               }
+       }
+       pfield_do_fill_line2 (start, stop, blank);
+}
+
+
+STATIC_INLINE void fill_line2 (int startpos, int len)
+{
+       int shift;
+       int nints, nrem;
+       int *start;
+       xcolnr val;
+
+       shift = 0;
+       if (gfxvidinfo.drawbuffer.pixbytes == 2)
+               shift = 1;
+       if (gfxvidinfo.drawbuffer.pixbytes == 4)
+               shift = 2;
+
+       nints = len >> (2 - shift);
+       nrem = nints & 7;
+       nints &= ~7;
+       start = (int *)(((uae_u8*)xlinebuffer) + (startpos << shift));
+       val = getbgc (false);
+       for (; nints > 0; nints -= 8, start += 8) {
+               *start = val;
+               *(start+1) = val;
+               *(start+2) = val;
+               *(start+3) = val;
+               *(start+4) = val;
+               *(start+5) = val;
+               *(start+6) = val;
+               *(start+7) = val;
+       }
+
+       switch (nrem) {
+       case 7:
+               *start++ = val;
+       case 6:
+               *start++ = val;
+       case 5:
+               *start++ = val;
+       case 4:
+               *start++ = val;
+       case 3:
+               *start++ = val;
+       case 2:
+               *start++ = val;
+       case 1:
+               *start = val;
+       }
+}
+
+static void fill_line (void)
+{
+       int hs = coord_hw_to_window_x (hsyncstartpos * 2);
+       if (hs >= gfxvidinfo.drawbuffer.inwidth || hposblank) {
+               hposblank = 3;
+               fill_line2 (visible_left_border, gfxvidinfo.drawbuffer.inwidth);
+       } else {
+               fill_line2 (visible_left_border, hs);
+               hposblank = 2;
+               fill_line2 (visible_left_border + hs, gfxvidinfo.drawbuffer.inwidth);
+       }
+}
+
+#define SPRITE_DEBUG 0
+STATIC_INLINE uae_u8 render_sprites (int pos, int dualpf, uae_u8 apixel, int aga)
+{
+       struct spritepixelsbuf *spb = &spritepixels[pos];
+       unsigned int v = spb->data;
+       int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms;
+       int maskshift, plfmask;
+
+       /* The value in the shift lookup table is _half_ the shift count we
+       need.  This is because we can't shift 32 bits at once (undefined
+       behaviour in C).  */
+       maskshift = shift_lookup[apixel];
+       plfmask = (plf_sprite_mask >> maskshift) >> maskshift;
+       v &= ~plfmask;
+       if (v != 0 || SPRITE_DEBUG) {
+               unsigned int vlo, vhi, col;
+               unsigned int v1 = v & 255;
+               /* OFFS determines the sprite pair with the highest priority that has
+               any bits set.  E.g. if we have 0xFF00 in the buffer, we have sprite
+               pairs 01 and 23 cleared, and pairs 45 and 67 set, so OFFS will
+               have a value of 4.
+               2 * OFFS is the bit number in V of the sprite pair, and it also
+               happens to be the color offset for that pair. 
+               */
+               int offs;
+               if (v1 == 0)
+                       offs = 4 + sprite_offs[v >> 8];
+               else
+                       offs = sprite_offs[v1];
+
+               /* Shift highest priority sprite pair down to bit zero.  */
+               v >>= offs * 2;
+               v &= 15;
+#if SPRITE_DEBUG > 0
+               v ^= 8;
+#endif
+               if (spb->attach && (spb->stdata & (3 << offs))) {
+                       col = v;
+                       if (aga)
+                               col += sbasecol[1];
+                       else
+                               col += 16;
+               } else {
+                       /* This sequence computes the correct color value.  We have to select
+                       either the lower-numbered or the higher-numbered sprite in the pair.
+                       We have to select the high one if the low one has all bits zero.
+                       If the lower-numbered sprite has any bits nonzero, (VLO - 1) is in
+                       the range of 0..2, and with the mask and shift, VHI will be zero.
+                       If the lower-numbered sprite is zero, (VLO - 1) is a mask of
+                       0xFFFFFFFF, and we select the bits of the higher numbered sprite
+                       in VHI.
+                       This is _probably_ more efficient than doing it with branches.  */
+                       vlo = v & 3;
+                       vhi = (v & (vlo - 1)) >> 2;
+                       col = (vlo | vhi);
+                       if (aga) {
+                               if (vhi > 0)
+                                       col += sbasecol[1];
+                               else
+                                       col += sbasecol[0];
+                       } else {
+                               col += 16;
+                       }
+                       col += offs * 2;
+               }
+
+               return col;
+       }
+
+       return 0;
+}
+
+#include "linetoscr.cpp"
+
+#define LTPARMS src_pixel, start, stop
+
+#ifdef ECS_DENISE
+/* ECS SuperHires special cases */
+
+#define PUTBPIX(x) buf[dpix] = (x);
+
+STATIC_INLINE uae_u32 shsprite (int dpix, uae_u32 spix_val, uae_u32 v, int spr)
+{
+       uae_u8 sprcol;
+       uae_u16 scol;
+       if (!spr)
+               return v;
+       sprcol = render_sprites (dpix, 0, spix_val, 0);
+       if (!sprcol)
+               return v;
+       /* good enough for now.. */ 
+       scol = colors_for_drawing.color_regs_ecs[sprcol] & 0xccc;
+       scol |= scol >> 2;
+       return xcolors[scol];
+}
+
+static int NOINLINE linetoscr_16_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u16 *buf = (uae_u16 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u16 spix_val1, spix_val2;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
+               dpix++;
+               v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
+               v |= v >> 2;
+               PUTBPIX(shsprite (dpix, spix_val2, xcolors[v], spr));
+               dpix++;
+       }
+       return spix;
+}
+static int NOINLINE linetoscr_32_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u32 *buf = (uae_u32 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u32 spix_val1, spix_val2;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
+               dpix++;
+               v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
+               v |= v >> 2;
+               PUTBPIX(shsprite (dpix, spix_val2, xcolors[v], spr));
+               dpix++;
+       }
+       return spix;
+}
+static int NOINLINE linetoscr_32_shrink1_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u32 *buf = (uae_u32 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u32 spix_val1, spix_val2;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
+               dpix++;
+       }
+       return spix;
+}
+static int NOINLINE linetoscr_32_shrink1f_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u32 *buf = (uae_u32 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u32 spix_val1, spix_val2, dpix_val1, dpix_val2;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               dpix_val1 = xcolors[v];
+               v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
+               v |= v >> 2;
+               dpix_val2 = xcolors[v];
+               PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel32 (dpix_val1, dpix_val2), spr));
+               dpix++;
+       }
+       return spix;
+}
+static int NOINLINE linetoscr_16_shrink1_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u16 *buf = (uae_u16 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u16 spix_val1, spix_val2;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
+               dpix++;
+       }
+       return spix;
+}
+static int NOINLINE linetoscr_16_shrink1f_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u16 *buf = (uae_u16 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u16 spix_val1, spix_val2, dpix_val1, dpix_val2;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               dpix_val1 = xcolors[v];
+               v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
+               v |= v >> 2;
+               dpix_val2 = xcolors[v];
+               PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel16 (dpix_val1, dpix_val2), spr));
+               dpix++;
+       }
+       return spix;
+}
+
+
+
+static int NOINLINE linetoscr_32_shrink2_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u32 *buf = (uae_u32 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u32 spix_val1, spix_val2;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
+               spix+=2;
+               dpix++;
+       }
+       return spix;
+}
+static int NOINLINE linetoscr_32_shrink2f_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u32 *buf = (uae_u32 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u32 spix_val1, spix_val2, dpix_val1, dpix_val2, dpix_val3, dpix_val4;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               dpix_val1 = xcolors[v];
+               v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
+               v |= v >> 2;
+               dpix_val2 = xcolors[v];
+               dpix_val3 = merge_2pixel32 (dpix_val1, dpix_val2);
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               dpix_val1 = xcolors[v];
+               v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
+               v |= v >> 2;
+               dpix_val2 = xcolors[v];
+               dpix_val4 = merge_2pixel32 (dpix_val1, dpix_val2);
+               PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel32 (dpix_val3, dpix_val4), spr));
+               dpix++;
+       }
+       return spix;
+}
+static int NOINLINE linetoscr_16_shrink2_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u16 *buf = (uae_u16 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u16 spix_val1, spix_val2;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
+               spix+=2;
+               dpix++;
+       }
+       return spix;
+}
+static int NOINLINE linetoscr_16_shrink2f_sh (int spix, int dpix, int stoppos, int spr)
+{
+       uae_u16 *buf = (uae_u16 *) xlinebuffer;
+
+       while (dpix < stoppos) {
+               uae_u16 spix_val1, spix_val2, dpix_val1, dpix_val2, dpix_val3, dpix_val4;
+               uae_u16 v;
+               int off;
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               dpix_val1 = xcolors[v];
+               v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
+               v |= v >> 2;
+               dpix_val2 = xcolors[v];
+               dpix_val3 = merge_2pixel32 (dpix_val1, dpix_val2);
+               spix_val1 = pixdata.apixels[spix++];
+               spix_val2 = pixdata.apixels[spix++];
+               off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
+               v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
+               v |= v >> 2;
+               dpix_val1 = xcolors[v];
+               v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
+               v |= v >> 2;
+               dpix_val2 = xcolors[v];
+               dpix_val4 = merge_2pixel32 (dpix_val1, dpix_val2);
+               PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel16 (dpix_val3, dpix_val4), spr));
+               dpix++;
+       }
+       return spix;
+}
+#endif
+
+static void pfield_do_linetoscr (int start, int stop, bool blank)
+{
+       xlinecheck(start, stop);
+       if (issprites && (currprefs.chipset_mask & CSMASK_AGA)) {
+               if (res_shift == 0) {
+                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                       case 2: src_pixel = linetoscr_16_aga_spr (LTPARMS); break;
+                       case 4: src_pixel = linetoscr_32_aga_spr (LTPARMS); break;
+                       }
+               } else if (res_shift == 2) {
+                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                       case 2: src_pixel = linetoscr_16_stretch2_aga_spr (LTPARMS); break;
+                       case 4: src_pixel = linetoscr_32_stretch2_aga_spr (LTPARMS); break;
+                       }
+               } else if (res_shift == 1) {
+                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                       case 2: src_pixel = linetoscr_16_stretch1_aga_spr (LTPARMS); break;
+                       case 4: src_pixel = linetoscr_32_stretch1_aga_spr (LTPARMS); break;
+                       }
+               } else if (res_shift == -1) {
+                       if (currprefs.gfx_lores_mode) {
+                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                               case 2: src_pixel = linetoscr_16_shrink1f_aga_spr (LTPARMS); break;
+                               case 4: src_pixel = linetoscr_32_shrink1f_aga_spr (LTPARMS); break;
+                               }
+                       } else {
+                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                               case 2: src_pixel = linetoscr_16_shrink1_aga_spr (LTPARMS); break;
+                               case 4: src_pixel = linetoscr_32_shrink1_aga_spr (LTPARMS); break;
+                               }
+                       }
+               } else if (res_shift == -2) {
+                       if (currprefs.gfx_lores_mode) {
+                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                               case 2: src_pixel = linetoscr_16_shrink2f_aga_spr (LTPARMS); break;
+                               case 4: src_pixel = linetoscr_32_shrink2f_aga_spr (LTPARMS); break;
+                               }
+                       } else {
+                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                               case 2: src_pixel = linetoscr_16_shrink2_aga_spr (LTPARMS); break;
+                               case 4: src_pixel = linetoscr_32_shrink2_aga_spr (LTPARMS); break;
+                               }
+                       }
+               }
+       } else
+#ifdef AGA
+               if (currprefs.chipset_mask & CSMASK_AGA) {
+                       if (res_shift == 0) {
+                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                               case 2: src_pixel = linetoscr_16_aga (LTPARMS); break;
+                               case 4: src_pixel = linetoscr_32_aga (LTPARMS); break;
+                               }
+                       } else if (res_shift == 2) {
+                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                               case 2: src_pixel = linetoscr_16_stretch2_aga (LTPARMS); break;
+                               case 4: src_pixel = linetoscr_32_stretch2_aga (LTPARMS); break;
+                               }
+                       } else if (res_shift == 1) {
+                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                               case 2: src_pixel = linetoscr_16_stretch1_aga (LTPARMS); break;
+                               case 4: src_pixel = linetoscr_32_stretch1_aga (LTPARMS); break;
+                               }
+                       } else if (res_shift == -1) {
+                               if (currprefs.gfx_lores_mode) {
+                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                       case 2: src_pixel = linetoscr_16_shrink1f_aga (LTPARMS); break;
+                                       case 4: src_pixel = linetoscr_32_shrink1f_aga (LTPARMS); break;
+                                       }
+                               } else {
+                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                       case 2: src_pixel = linetoscr_16_shrink1_aga (LTPARMS); break;
+                                       case 4: src_pixel = linetoscr_32_shrink1_aga (LTPARMS); break;
+                                       }
+                               }
+                       } else if (res_shift == -2) {
+                               if (currprefs.gfx_lores_mode) {
+                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                       case 2: src_pixel = linetoscr_16_shrink2f_aga (LTPARMS); break;
+                                       case 4: src_pixel = linetoscr_32_shrink2f_aga (LTPARMS); break;
+                                       }
+                               } else {
+                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                       case 2: src_pixel = linetoscr_16_shrink2_aga (LTPARMS); break;
+                                       case 4: src_pixel = linetoscr_32_shrink2_aga (LTPARMS); break;
+                                       }
+                               }
+                       }
+               } else
+#endif
+#ifdef ECS_DENISE
+                       if (ecsshres) {
+                               if (res_shift == 0) {
+                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                       case 2: src_pixel = linetoscr_16_sh (LTPARMS, issprites); break;
+                                       case 4: src_pixel = linetoscr_32_sh (LTPARMS, issprites); break;
+                                       }
+                               } else if (res_shift == -1) {
+                                       if (currprefs.gfx_lores_mode) {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_shrink1f_sh (LTPARMS, issprites); break;
+                                               case 4: src_pixel = linetoscr_32_shrink1f_sh (LTPARMS, issprites); break;
+                                               }
+                                       } else {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_shrink1_sh (LTPARMS, issprites); break;
+                                               case 4: src_pixel = linetoscr_32_shrink1_sh (LTPARMS, issprites); break;
+                                               }
+                                       }
+                               } else if (res_shift == -2) {
+                                       if (currprefs.gfx_lores_mode) {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_shrink2f_sh (LTPARMS, issprites); break;
+                                               case 4: src_pixel = linetoscr_32_shrink2f_sh (LTPARMS, issprites); break;
+                                               }
+                                       } else {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_shrink2_sh (LTPARMS, issprites); break;
+                                               case 4: src_pixel = linetoscr_32_shrink2_sh (LTPARMS, issprites); break;
+                                               }
+                                       }
+                               }
+                       } else
+#endif
+                               if (issprites) {
+                                       if (res_shift == 0) {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_spr (LTPARMS); break;
+                                               case 4: src_pixel = linetoscr_32_spr (LTPARMS); break;
+                                               }
+                                       } else if (res_shift == 2) {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_stretch2_spr (LTPARMS); break;
+                                               case 4: src_pixel = linetoscr_32_stretch2_spr (LTPARMS); break;
+                                               }
+                                       } else if (res_shift == 1) {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_stretch1_spr (LTPARMS); break;
+                                               case 4: src_pixel = linetoscr_32_stretch1_spr (LTPARMS); break;
+                                               }
+                                       } else if (res_shift == -1) {
+                                               if (currprefs.gfx_lores_mode) {
+                                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                                       case 2: src_pixel = linetoscr_16_shrink1f_spr (LTPARMS); break;
+                                                       case 4: src_pixel = linetoscr_32_shrink1f_spr (LTPARMS); break;
+                                                       }
+                                               } else {
+                                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                                       case 2: src_pixel = linetoscr_16_shrink1_spr (LTPARMS); break;
+                                                       case 4: src_pixel = linetoscr_32_shrink1_spr (LTPARMS); break;
+                                                       }
+                                               }
+                                       }
+                               } else {
+                                       if (res_shift == 0) {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16 (LTPARMS); break;
+                                               case 4: src_pixel = linetoscr_32 (LTPARMS); break;
+                                               }
+                                       } else if (res_shift == 2) {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_stretch2 (LTPARMS); break;
+                                               case 4: src_pixel = linetoscr_32_stretch2 (LTPARMS); break;
+                                               }
+                                       } else if (res_shift == 1) {
+                                               switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                               case 2: src_pixel = linetoscr_16_stretch1 (LTPARMS); break;
+                                               case 4: src_pixel = linetoscr_32_stretch1 (LTPARMS); break;
+                                               }
+                                       } else if (res_shift == -1) {
+                                               if (currprefs.gfx_lores_mode) {
+                                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                                       case 2: src_pixel = linetoscr_16_shrink1f (LTPARMS); break;
+                                                       case 4: src_pixel = linetoscr_32_shrink1f (LTPARMS); break;
+                                                       }
+                                               } else {
+                                                       switch (gfxvidinfo.drawbuffer.pixbytes) {
+                                                       case 2: src_pixel = linetoscr_16_shrink1 (LTPARMS); break;
+                                                       case 4: src_pixel = linetoscr_32_shrink1 (LTPARMS); break;
+                                                       }
+                                               }
+                                       }
+                               }
+
+}
+
+static void dummy_worker (int start, int stop, bool blank)
+{
+}
+
+static int ham_decode_pixel;
+static unsigned int ham_lastcolor;
+
+/* Decode HAM in the invisible portion of the display (left of VISIBLE_LEFT_BORDER),
+ * but don't draw anything in.  This is done to prepare HAM_LASTCOLOR for later,
+ * when decode_ham runs.
+ *
+ */
+static void init_ham_decoding (void)
+{
+       int unpainted_amiga = unpainted;
+
+       ham_decode_pixel = ham_src_pixel;
+       ham_lastcolor = color_reg_get (&colors_for_drawing, 0);
+
+       if (!bplham) {
+               if (unpainted_amiga > 0) {
+                       int pv = pixdata.apixels[ham_decode_pixel + unpainted_amiga - 1];
+#ifdef AGA
+                       if (currprefs.chipset_mask & CSMASK_AGA)
+                               ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor];
+                       else
+#endif
+                               ham_lastcolor = colors_for_drawing.color_regs_ecs[pv];
+               }
+#ifdef AGA
+       } else if (currprefs.chipset_mask & CSMASK_AGA) {
+               if (bplplanecnt >= 7) { /* AGA mode HAM8 */
+                       while (unpainted_amiga-- > 0) {
+                               int pv = pixdata.apixels[ham_decode_pixel++] ^ bplxor;
+                               switch (pv & 0x3)
+                               {
+                               case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break;
+                               case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break;
+                               case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break;
+                               case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break;
+                               }
+                       }
+               } else { /* AGA mode HAM6 */
+                       while (unpainted_amiga-- > 0) {
+                               int pv = pixdata.apixels[ham_decode_pixel++] ^ bplxor;
+                               switch (pv & 0x30)
+                               {
+                               case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break;
+                               case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break;
+                               case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break;
+                               case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break;
+                               }
+                       }
+               }
+#endif
+       } else {
+               /* OCS/ECS mode HAM6 */
+               while (unpainted_amiga-- > 0) {
+                       int pv = pixdata.apixels[ham_decode_pixel++];
+                       switch (pv & 0x30)
+                       {
+                       case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break;
+                       case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break;
+                       case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break;
+                       case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break;
+                       }
+               }
+       }
+}
+
+static void decode_ham (int pix, int stoppos, bool blank)
+{
+       int todraw_amiga = res_shift_from_window (stoppos - pix);
+
+       if (!bplham) {
+               while (todraw_amiga-- > 0) {
+                       int pv = pixdata.apixels[ham_decode_pixel];
+#ifdef AGA
+                       if (currprefs.chipset_mask & CSMASK_AGA)
+                               ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor];
+                       else
+#endif
+                               ham_lastcolor = colors_for_drawing.color_regs_ecs[pv];
+
+                       ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
+               }
+#ifdef AGA
+       } else if (currprefs.chipset_mask & CSMASK_AGA) {
+               if (bplplanecnt >= 7) { /* AGA mode HAM8 */
+                       while (todraw_amiga-- > 0) {
+                               int pv = pixdata.apixels[ham_decode_pixel] ^ bplxor;
+                               switch (pv & 0x3)
+                               {
+                               case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2]; break;
+                               case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break;
+                               case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break;
+                               case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break;
+                               }
+                               ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
+                       }
+               } else { /* AGA mode HAM6 */
+                       while (todraw_amiga-- > 0) {
+                               int pv = pixdata.apixels[ham_decode_pixel] ^ bplxor;
+                               switch (pv & 0x30)
+                               {
+                               case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv]; break;
+                               case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= (pv & 0xF) << 4; break;
+                               case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= (pv & 0xF) << 20; break;
+                               case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= (pv & 0xF) << 12; break;
+                               }
+                               ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
+                       }
+               }
+#endif
+       } else {
+               /* OCS/ECS mode HAM6 */
+               while (todraw_amiga-- > 0) {
+                       int pv = pixdata.apixels[ham_decode_pixel];
+                       switch (pv & 0x30)
+                       {
+                       case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv]; break;
+                       case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break;
+                       case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break;
+                       case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break;
+                       }
+                       ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
+               }
+       }
+}
+
+static void gen_pfield_tables (void)
+{
+       int i;
+
+       for (i = 0; i < 256; i++) {
+               int plane1 = ((i >> 0) & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8);
+               int plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8);
+
+               dblpf_2nd1[i] = plane1 == 0 && plane2 != 0;
+               dblpf_2nd2[i] = plane2 != 0;
+
+#ifdef AGA
+               dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1;
+               dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2;
+#endif
+
+               dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0;
+               dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8;
+               dblpf_ms[i] = i == 0 ? 16 : 8;
+
+               if (plane2 > 0)
+                       plane2 += 8;
+               dblpf_ind1[i] = i >= 128 ? i & 0x7F : (plane1 == 0 ? plane2 : plane1);
+               dblpf_ind2[i] = i >= 128 ? i & 0x7F : (plane2 == 0 ? plane1 : plane2);
+
+               sprite_offs[i] = (i & 15) ? 0 : 2;
+
+               clxtab[i] = ((((i & 3) && (i & 12)) << 9)
+                       | (((i & 3) && (i & 48)) << 10)
+                       | (((i & 3) && (i & 192)) << 11)
+                       | (((i & 12) && (i & 48)) << 12)
+                       | (((i & 12) && (i & 192)) << 13)
+                       | (((i & 48) && (i & 192)) << 14));
+
+       }
+
+       memset (all_ones, 0xff, MAX_PIXELS_PER_LINE);
+
+}
+
+/* When looking at this function and the ones that inline it, bear in mind
+what an optimizing compiler will do with this code.  All callers of this
+function only pass in constant arguments (except for E).  This means
+that many of the if statements will go away completely after inlining.  */
+STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int dualpf, int has_attach)
+{
+       uae_u16 *buf = spixels + e->first_pixel;
+       uae_u8 *stbuf = spixstate.bytes + e->first_pixel;
+       int spr_pos, pos;
+
+       buf -= e->pos;
+       stbuf -= e->pos;
+
+       spr_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << sprite_buffer_res);
+
+       if (spr_pos < sprite_first_x)
+               sprite_first_x = spr_pos;
+
+       for (pos = e->pos; pos < e->max; pos++, spr_pos++) {
+               if (spr_pos >= 0 && spr_pos < MAX_PIXELS_PER_LINE) {
+                       spritepixels[spr_pos].data = buf[pos];
+                       spritepixels[spr_pos].stdata = stbuf[pos];
+                       spritepixels[spr_pos].attach = has_attach;
+               }
+       }
+
+       if (spr_pos > sprite_last_x)
+               sprite_last_x = spr_pos;
+}
+
+/* See comments above.  Do not touch if you don't know what's going on.
+* (We do _not_ want the following to be inlined themselves).  */
+/* lores bitplane, lores sprites */
+static void NOINLINE draw_sprites_normal_sp_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0); }
+static void NOINLINE draw_sprites_normal_dp_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0); }
+static void NOINLINE draw_sprites_normal_sp_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1); }
+static void NOINLINE draw_sprites_normal_dp_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 1); }
+
+#ifdef AGA
+/* not very optimized */
+STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e, int aga)
+{
+       draw_sprites_1 (e, bpldualpf, e->has_attached);
+}
+#endif
+
+STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e)
+{
+       if (e->has_attached) {
+               if (bpldualpf)
+                       draw_sprites_normal_dp_at (e);
+               else
+                       draw_sprites_normal_sp_at (e);
+       } else {
+               if (bpldualpf)
+                       draw_sprites_normal_dp_nat (e);
+               else
+                       draw_sprites_normal_sp_nat (e);
+       }
+}
+
+#ifdef AGA
+/* clear possible bitplane data outside DIW area */
+static void clear_bitplane_border_aga (void)
+{
+       int len, shift = res_shift;
+       uae_u8 v = 0;
+
+       if (shift < 0) {
+               shift = -shift;
+               len = (real_playfield_start - playfield_start) << shift;
+               memset (pixdata.apixels + pixels_offset + (playfield_start << shift), v, len);
+               len = (playfield_end - real_playfield_end) << shift;
+               memset (pixdata.apixels + pixels_offset + (real_playfield_end << shift), v, len);
+       } else {
+               len = (real_playfield_start - playfield_start) >> shift;
+               memset (pixdata.apixels + pixels_offset + (playfield_start >> shift), v, len);
+               len = (playfield_end - real_playfield_end) >> shift;
+               memset (pixdata.apixels + pixels_offset + (real_playfield_end >> shift), v, len);
+       }
+}
+#endif
+
+/* emulate OCS/ECS only undocumented "SWIV" hardware feature */
+static void weird_bitplane_fix (void)
+{
+       int i;
+       int sh = lores_shift;
+       uae_u8 *p = pixdata.apixels + pixels_offset;
+
+       for (i = playfield_start >> sh; i < playfield_end >> sh; i++) {
+               if (p[i] > 16)
+                       p[i] = 16;
+       }
+}
+
+#define MERGE(a,b,mask,shift) do {\
+       uae_u32 tmp = mask & (a ^ (b >> shift)); \
+       a ^= tmp; \
+       b ^= (tmp << shift); \
+} while (0)
+
+#define GETLONG(P) (*(uae_u32 *)P)
+
+/* We use the compiler's inlining ability to ensure that PLANES is in effect a compile time
+constant.  That will cause some unnecessary code to be optimized away.
+Don't touch this if you don't know what you are doing.  */
+STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int wordcount, int planes)
+{
+       while (wordcount-- > 0) {
+               uae_u32 b0, b1, b2, b3, b4, b5, b6, b7;
+
+               b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0;
+               switch (planes) {
+#ifdef AGA
+               case 8: b0 = GETLONG (real_bplpt[7]); real_bplpt[7] += 4;
+               case 7: b1 = GETLONG (real_bplpt[6]); real_bplpt[6] += 4;
+#endif
+               case 6: b2 = GETLONG (real_bplpt[5]); real_bplpt[5] += 4;
+               case 5: b3 = GETLONG (real_bplpt[4]); real_bplpt[4] += 4;
+               case 4: b4 = GETLONG (real_bplpt[3]); real_bplpt[3] += 4;
+               case 3: b5 = GETLONG (real_bplpt[2]); real_bplpt[2] += 4;
+               case 2: b6 = GETLONG (real_bplpt[1]); real_bplpt[1] += 4;
+               case 1: b7 = GETLONG (real_bplpt[0]); real_bplpt[0] += 4;
+               }
+
+               MERGE (b0, b1, 0x55555555, 1);
+               MERGE (b2, b3, 0x55555555, 1);
+               MERGE (b4, b5, 0x55555555, 1);
+               MERGE (b6, b7, 0x55555555, 1);
+
+               MERGE (b0, b2, 0x33333333, 2);
+               MERGE (b1, b3, 0x33333333, 2);
+               MERGE (b4, b6, 0x33333333, 2);
+               MERGE (b5, b7, 0x33333333, 2);
+
+               MERGE (b0, b4, 0x0f0f0f0f, 4);
+               MERGE (b1, b5, 0x0f0f0f0f, 4);
+               MERGE (b2, b6, 0x0f0f0f0f, 4);
+               MERGE (b3, b7, 0x0f0f0f0f, 4);
+
+               MERGE (b0, b1, 0x00ff00ff, 8);
+               MERGE (b2, b3, 0x00ff00ff, 8);
+               MERGE (b4, b5, 0x00ff00ff, 8);
+               MERGE (b6, b7, 0x00ff00ff, 8);
+
+               MERGE (b0, b2, 0x0000ffff, 16);
+               do_put_mem_long (pixels, b0);
+               do_put_mem_long (pixels + 4, b2);
+               MERGE (b1, b3, 0x0000ffff, 16);
+               do_put_mem_long (pixels + 2, b1);
+               do_put_mem_long (pixels + 6, b3);
+               MERGE (b4, b6, 0x0000ffff, 16);
+               do_put_mem_long (pixels + 1, b4);
+               do_put_mem_long (pixels + 5, b6);
+               MERGE (b5, b7, 0x0000ffff, 16);
+               do_put_mem_long (pixels + 3, b5);
+               do_put_mem_long (pixels + 7, b7);
+               pixels += 8;
+       }
+}
+
+/* See above for comments on inlining.  These functions should _not_
+be inlined themselves.  */
+static void NOINLINE pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); }
+static void NOINLINE pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); }
+static void NOINLINE pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); }
+static void NOINLINE pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); }
+static void NOINLINE pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); }
+static void NOINLINE pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); }
+#ifdef AGA
+static void NOINLINE pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); }
+static void NOINLINE pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); }
+#endif
+
+static void pfield_doline (int lineno)
+{
+       int wordcount = dp_for_drawing->plflinelen;
+       uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE / 4;
+
+#ifdef SMART_UPDATE
+#define DATA_POINTER(n) ((debug_bpl_mask & (1 << n)) ? (line_data[lineno] + (n) * MAX_WORDS_PER_LINE * 2) : (debug_bpl_mask_one ? all_ones : all_zeros))
+       real_bplpt[0] = DATA_POINTER (0);
+       real_bplpt[1] = DATA_POINTER (1);
+       real_bplpt[2] = DATA_POINTER (2);
+       real_bplpt[3] = DATA_POINTER (3);
+       real_bplpt[4] = DATA_POINTER (4);
+       real_bplpt[5] = DATA_POINTER (5);
+#ifdef AGA
+       real_bplpt[6] = DATA_POINTER (6);
+       real_bplpt[7] = DATA_POINTER (7);
+#endif
+#endif
+
+       switch (bplplanecnt) {
+       default: break;
+       case 0: memset (data, 0, wordcount * 32); break;
+       case 1: pfield_doline_n1 (data, wordcount); break;
+       case 2: pfield_doline_n2 (data, wordcount); break;
+       case 3: pfield_doline_n3 (data, wordcount); break;
+       case 4: pfield_doline_n4 (data, wordcount); break;
+       case 5: pfield_doline_n5 (data, wordcount); break;
+       case 6: pfield_doline_n6 (data, wordcount); break;
+#ifdef AGA
+       case 7: pfield_doline_n7 (data, wordcount); break;
+       case 8: pfield_doline_n8 (data, wordcount); break;
+#endif
+       }
+}
+
+void init_row_map (void)
+{
+       static uae_u8 *oldbufmem;
+       static int oldheight, oldpitch;
+
+       int i, j;
+       if (gfxvidinfo.drawbuffer.height_allocated > MAX_VIDHEIGHT) {
+               write_log (_T("Resolution too high, aborting\n"));
+               abort ();
+       }
+       if (oldbufmem && oldbufmem == gfxvidinfo.drawbuffer.bufmem &&
+               oldheight == gfxvidinfo.drawbuffer.height_allocated &&
+               oldpitch == gfxvidinfo.drawbuffer.rowbytes)
+               return;
+       oldbufmem = gfxvidinfo.drawbuffer.bufmem;
+       oldheight = gfxvidinfo.drawbuffer.height_allocated;
+       oldpitch = gfxvidinfo.drawbuffer.rowbytes;
+       j = 0;
+       for (i = gfxvidinfo.drawbuffer.height_allocated; i < MAX_VIDHEIGHT + 1; i++)
+               row_map[i] = row_tmp;
+       for (i = 0; i < gfxvidinfo.drawbuffer.height_allocated; i++, j += gfxvidinfo.drawbuffer.rowbytes)
+               row_map[i] = gfxvidinfo.drawbuffer.bufmem + j;
+}
+
+void init_aspect_maps (void)
+{
+       int i, maxl, h;
+
+       h = gfxvidinfo.drawbuffer.height_allocated;
+
+       if (h == 0)
+               /* Do nothing if the gfx driver hasn't initialized the screen yet */
+               return;
+
+       linedbld = linedbl = currprefs.gfx_vresolution;
+       if (doublescan > 0 && interlace_seen <= 0) {
+               linedbl = 0;
+               linedbld = 1;
+       }
+
+       if (native2amiga_line_map)
+               xfree (native2amiga_line_map);
+       if (amiga2aspect_line_map)
+               xfree (amiga2aspect_line_map);
+
+       /* At least for this array the +1 is necessary. */
+       amiga2aspect_line_map = xmalloc (int, (MAXVPOS + 1) * 2 + 1);
+       native2amiga_line_map = xmalloc (int, h);
+
+       maxl = (MAXVPOS + 1) << linedbld;
+       min_ypos_for_screen = minfirstline << linedbl;
+       max_drawn_amiga_line = -1;
+       for (i = 0; i < maxl; i++) {
+               int v = i - min_ypos_for_screen;
+               if (v >= h && max_drawn_amiga_line < 0)
+                       max_drawn_amiga_line = i - min_ypos_for_screen;
+               if (i < min_ypos_for_screen || v >= h)
+                       v = -1;
+               amiga2aspect_line_map[i] = v;
+       }
+       if (max_drawn_amiga_line < 0)
+               max_drawn_amiga_line = maxl - min_ypos_for_screen;
+       max_drawn_amiga_line >>= linedbl;
+
+       if (currprefs.gfx_ycenter && !currprefs.gfx_filter_autoscale) {
+               /* @@@ verify maxvpos vs. MAXVPOS */
+               extra_y_adjust = (h - (maxvpos_nom << linedbl)) >> 1;
+               if (extra_y_adjust < 0)
+                       extra_y_adjust = 0;
+       }
+
+       for (i = 0; i < h; i++)
+               native2amiga_line_map[i] = -1;
+
+       for (i = maxl - 1; i >= min_ypos_for_screen; i--) {
+               int j;
+               if (amiga2aspect_line_map[i] == -1)
+                       continue;
+               for (j = amiga2aspect_line_map[i]; j < h && native2amiga_line_map[j] == -1; j++)
+                       native2amiga_line_map[j] = i >> linedbl;
+       }
+
+       gfxvidinfo.xchange = 1 << (RES_MAX - currprefs.gfx_resolution);
+       gfxvidinfo.ychange = linedbl ? 1 : 2;
+
+       visible_left_start = 0;
+       visible_right_stop = MAX_STOP;
+       visible_top_start = 0;
+       visible_bottom_stop = MAX_STOP;
+}
+
+/*
+* A raster line has been built in the graphics buffer. Tell the graphics code
+* to do anything necessary to display it.
+*/
+static void do_flush_line_1 (struct vidbuffer *vb, int lineno)
+{
+       if (lineno < first_drawn_line)
+               first_drawn_line = lineno;
+       if (lineno > last_drawn_line)
+               last_drawn_line = lineno;
+
+       if (gfxvidinfo.maxblocklines == 0)
+               flush_line (vb, lineno);
+       else {
+               if ((last_block_line + 2) < lineno) {
+                       if (first_block_line != NO_BLOCK)
+                               flush_block (vb, first_block_line, last_block_line);
+                       first_block_line = lineno;
+               }
+               last_block_line = lineno;
+               if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) {
+                       flush_block (vb, first_block_line, last_block_line);
+                       first_block_line = last_block_line = NO_BLOCK;
+               }
+       }
+}
+
+STATIC_INLINE void do_flush_line (struct vidbuffer *vb, int lineno)
+{
+       do_flush_line_1 (vb, lineno);
+}
+
+/*
+* One drawing frame has been finished. Tell the graphics code about it.
+* Note that the actual flush_screen() call is a no-op for all reasonable
+* systems.
+*/
+
+STATIC_INLINE void do_flush_screen (struct vidbuffer *vb, int start, int stop)
+{
+       /* TODO: this flush operation is executed outside locked state!
+       Should be corrected.
+       (sjo 26.9.99) */
+
+       if (vb != gfxvidinfo.outbuffer)
+               return;
+
+       xlinecheck (start, stop);
+       if (gfxvidinfo.maxblocklines != 0 && first_block_line != NO_BLOCK) {
+               flush_block (vb, first_block_line, last_block_line);
+       }
+       unlockscr (vb);
+       if (start <= stop)
+               flush_screen (vb, start, stop);
+       else if (isvsync_chipset ())
+               flush_screen (vb, 0, 0); /* vsync mode */
+}
+
+/* We only save hardware registers during the hardware frame. Now, when
+* drawing the frame, we expand the data into a slightly more useful
+* form. */
+static void pfield_expand_dp_bplcon (void)
+{
+       static int b2;
+
+       bplres = dp_for_drawing->bplres;
+       bplplanecnt = dp_for_drawing->nr_planes;
+       bplham = dp_for_drawing->ham_seen;
+       bplehb = dp_for_drawing->ehb_seen;
+       if ((currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon2 & 0x0200))
+               bplehb = 0;
+       issprites = dip_for_drawing->nr_sprites;
+#ifdef ECS_DENISE
+       ecsshres = bplres == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA);
+#endif
+
+       plf1pri = dp_for_drawing->bplcon2 & 7;
+       plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7;
+       plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri);
+       plf_sprite_mask |= (0x0000FFFF << (4 * plf1pri)) & 0xFFFF;
+       bpldualpf = (dp_for_drawing->bplcon0 & 0x400) == 0x400;
+       bpldualpfpri = (dp_for_drawing->bplcon2 & 0x40) == 0x40;
+
+#ifdef AGA
+       bpldualpf2of = (dp_for_drawing->bplcon3 >> 10) & 7;
+       sbasecol[0] = ((dp_for_drawing->bplcon4 >> 4) & 15) << 4;
+       sbasecol[1] = ((dp_for_drawing->bplcon4 >> 0) & 15) << 4;
+       brdsprt = !brdblank && (currprefs.chipset_mask & CSMASK_AGA) && (dp_for_drawing->bplcon0 & 1) && (dp_for_drawing->bplcon3 & 0x02);
+       bplxor = dp_for_drawing->bplcon4 >> 8;
+#endif
+}
+
+static bool isham (uae_u16 bplcon0)
+{
+       int p = GET_PLANES (bplcon0);
+       if (!(bplcon0 & 0x800))
+               return 0;
+       if (currprefs.chipset_mask & CSMASK_AGA) {
+               // AGA only has 6 or 8 plane HAM
+               if (p == 6 || p == 8)
+                       return 1;
+       } else {
+               // OCS/ECS also supports 5 plane HAM
+               if (GET_RES_DENISE (bplcon0) > 0)
+                       return 0;
+               if (p >= 5)
+                       return 1;
+       }
+       return 0;
+}
+
+static void isbrdblank (void)
+{
+#ifdef ECS_DENISE
+       bool brdblank_2 = (currprefs.chipset_mask & CSMASK_ECS_DENISE) && (bplcon0_store & 1) && (bplcon3_store & 0x20);
+       if (brdblank_2 != brdblank)
+               brdblank_changed = true;
+       brdblank = brdblank_2;
+#endif
+}
+
+static void pfield_expand_dp_bplconx (int regno, int v)
+{
+       if (regno == 0xffff) {
+               hposblank = 1;
+               return;
+       }
+       regno -= 0x1000;
+       switch (regno)
+       {
+       case 0x100:
+               dp_for_drawing->bplcon0 = v;
+               dp_for_drawing->bplres = GET_RES_DENISE (v);
+               dp_for_drawing->nr_planes = GET_PLANES (v);
+               dp_for_drawing->ham_seen = isham (v);
+               bplcon0_store = v;
+               isbrdblank ();
+               break;
+       case 0x104:
+               dp_for_drawing->bplcon2 = v;
+               break;
+#ifdef ECS_DENISE
+       case 0x106:
+               dp_for_drawing->bplcon3 = v;
+               bplcon3_store = v;
+               isbrdblank ();
+               break;
+#endif
+#ifdef AGA
+       case 0x10c:
+               dp_for_drawing->bplcon4 = v;
+               break;
+#endif
+       }
+       pfield_expand_dp_bplcon ();
+       res_shift = lores_shift - bplres;
+}
+
+static int drawing_color_matches;
+static enum { color_match_acolors, color_match_full } color_match_type;
+
+/* Set up colors_for_drawing to the state at the beginning of the currently drawn
+line.  Try to avoid copying color tables around whenever possible.  */
+static void adjust_drawing_colors (int ctable, int need_full)
+{
+       if (drawing_color_matches != ctable) {
+               if (need_full) {
+                       color_reg_cpy (&colors_for_drawing, curr_color_tables + ctable);
+                       color_match_type = color_match_full;
+               } else {
+                       memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors,
+                               sizeof colors_for_drawing.acolors);
+                       color_match_type = color_match_acolors;
+               }
+               drawing_color_matches = ctable;
+       } else if (need_full && color_match_type != color_match_full) {
+               color_reg_cpy (&colors_for_drawing, &curr_color_tables[ctable]);
+               color_match_type = color_match_full;
+       }
+}
+
+static void do_color_changes (line_draw_func worker_border, line_draw_func worker_pfield, int vp)
+{
+       int i;
+       int lastpos = visible_left_border;
+       int endpos = visible_left_border + gfxvidinfo.drawbuffer.inwidth;
+
+       for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++) {
+               int regno = curr_color_changes[i].regno;
+               unsigned int value = curr_color_changes[i].value;
+               int nextpos, nextpos_in_range;
+
+               if (i == dip_for_drawing->last_color_change)
+                       nextpos = endpos;
+               else
+                       nextpos = coord_hw_to_window_x (curr_color_changes[i].linepos);
+
+               nextpos_in_range = nextpos;
+               if (nextpos > endpos)
+                       nextpos_in_range = endpos;
+
+               if (nextpos_in_range > lastpos) {
+                       if (lastpos < playfield_start) {
+                               int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
+                               (*worker_border) (lastpos, t, false);
+                               lastpos = t;
+                       }
+               }
+               if (nextpos_in_range > lastpos) {
+                       if (lastpos >= playfield_start && lastpos < playfield_end) {
+                               int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
+                               (*worker_pfield) (lastpos, t, false);
+                               /* blank start and end that shouldn't be visible */
+                               if (lastpos < visible_left_start)
+                                       (*worker_border) (lastpos, visible_left_start, true);
+                               if (t > visible_right_stop)
+                                       (*worker_border) (visible_right_stop, endpos, true);
+                               lastpos = t;
+                       }
+               }
+               if (nextpos_in_range > lastpos) {
+                       if (lastpos >= playfield_end)
+                               (*worker_border) (lastpos, nextpos_in_range, false);
+                       lastpos = nextpos_in_range;
+               }
+
+               if (regno >= 0x1000) {
+                       pfield_expand_dp_bplconx (regno, value);
+               } else if (regno >= 0) {
+                       color_reg_set (&colors_for_drawing, regno, value);
+                       colors_for_drawing.acolors[regno] = getxcolor (value);
+               }
+               if (lastpos >= endpos)
+                       break;
+       }
+       if (vp < visible_top_start || vp >= visible_bottom_stop) {
+               // outside of visible area
+               // Just overwrite with black. Above code needs to run because of custom registers,
+               // not worth the trouble for separate code path just for max 10 lines or so
+               (*worker_border) (visible_left_border, visible_left_border + gfxvidinfo.drawbuffer.inwidth, true);
+       }
+
+}
+enum double_how {
+       dh_buf,
+       dh_line,
+       dh_emerg
+};
+
+static void pfield_draw_line (struct vidbuffer *vb, int lineno, int gfx_ypos, int follow_ypos)
+{
+       static int warned = 0;
+       int border = 0;
+       int do_double = 0;
+       enum double_how dh;
+
+       dp_for_drawing = line_decisions + lineno;
+       dip_for_drawing = curr_drawinfo + lineno;
+
+       switch (linestate[lineno])
+       {
+       case LINE_REMEMBERED_AS_PREVIOUS:
+//             if (!warned) // happens when program messes up with VPOSW
+//                     write_log (_T("Shouldn't get here... this is a bug.\n")), warned++;
+               return;
+
+       case LINE_BLACK:
+               linestate[lineno] = LINE_REMEMBERED_AS_BLACK;
+               border = 2;
+               break;
+
+       case LINE_REMEMBERED_AS_BLACK:
+               return;
+
+       case LINE_AS_PREVIOUS:
+               dp_for_drawing--;
+               dip_for_drawing--;
+               linestate[lineno] = LINE_DONE_AS_PREVIOUS;
+               if (dp_for_drawing->plfleft < 0)
+                       border = 1;
+               break;
+
+       case LINE_DONE_AS_PREVIOUS:
+               /* fall through */
+       case LINE_DONE:
+               return;
+
+       case LINE_DECIDED_DOUBLE:
+               if (follow_ypos >= 0) {
+                       do_double = 1;
+                       linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS;
+               }
+
+               /* fall through */
+       default:
+               if (dp_for_drawing->plfleft < 0)
+                       border = 1;
+               linestate[lineno] = LINE_DONE;
+               break;
+       }
+
+       dh = dh_line;
+       xlinebuffer = gfxvidinfo.drawbuffer.linemem;
+       if (xlinebuffer == 0 && do_double
+               && (border == 0 || dip_for_drawing->nr_color_changes > 0))
+               xlinebuffer = gfxvidinfo.drawbuffer.emergmem, dh = dh_emerg;
+       if (xlinebuffer == 0)
+               xlinebuffer = row_map[gfx_ypos], dh = dh_buf;
+       xlinebuffer -= linetoscr_x_adjust_bytes;
+
+       if (border == 0) {
+
+               pfield_expand_dp_bplcon ();
+               pfield_init_linetoscr ();
+               pfield_doline (lineno);
+
+               adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb || ecsshres);
+
+               /* The problem is that we must call decode_ham() BEFORE we do the
+               sprites. */
+               if (dp_for_drawing->ham_seen) {
+                       init_ham_decoding ();
+                       if (dip_for_drawing->nr_color_changes == 0) {
+                               /* The easy case: need to do HAM decoding only once for the
+                               * full line. */
+                               decode_ham (visible_left_border, visible_right_border, false);
+                       } else /* Argh. */ {
+                               do_color_changes (dummy_worker, decode_ham, lineno);
+                               adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb);
+                       }
+                       bplham = dp_for_drawing->ham_at_start;
+               }
+
+               if (plf2pri > 5 && bplplanecnt == 5 && !(currprefs.chipset_mask & CSMASK_AGA))
+                       weird_bitplane_fix ();
+
+               if (dip_for_drawing->nr_sprites) {
+                       int i;
+#ifdef AGA
+                       if (brdsprt)
+                               clear_bitplane_border_aga ();
+#endif
+                       for (i = 0; i < dip_for_drawing->nr_sprites; i++) {
+#ifdef AGA
+                               if (currprefs.chipset_mask & CSMASK_AGA)
+                                       draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i, 1);
+                               else
+#endif
+                                       draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i);
+                       }
+               }
+
+               do_color_changes (pfield_do_fill_line, pfield_do_linetoscr, lineno);
+
+               if (dh == dh_emerg)
+                       memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
+
+               do_flush_line (vb, gfx_ypos);
+               if (do_double) {
+                       if (dh == dh_emerg)
+                               memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
+                       else if (dh == dh_buf)
+                               memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
+                       do_flush_line (vb, follow_ypos);
+               }
+
+       } else if (border == 1) {
+               int dosprites = 0;
+
+               adjust_drawing_colors (dp_for_drawing->ctable, 0);
+
+#ifdef AGA /* this makes things complex.. */
+               if (brdsprt && dip_for_drawing->nr_sprites > 0) {
+                       dosprites = 1;
+                       pfield_expand_dp_bplcon ();
+                       pfield_init_linetoscr ();
+                       memset (pixdata.apixels + MAX_PIXELS_PER_LINE, brdblank ? 0 : colors_for_drawing.acolors[0], MAX_PIXELS_PER_LINE);
+               }
+#endif
+
+               if (!dosprites && dip_for_drawing->nr_color_changes == 0) {
+                       fill_line ();
+                       do_flush_line (vb, gfx_ypos);
+
+                       if (do_double) {
+                               if (dh == dh_buf) {
+                                       xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_bytes;
+                                       fill_line ();
+                               }
+                               /* If dh == dh_line, do_flush_line will re-use the rendered line
+                               * from linemem.  */
+                               do_flush_line (vb, follow_ypos);
+                       }
+                       return;
+               }
+
+
+               if (dosprites) {
+
+                       int i;
+                       for (i = 0; i < dip_for_drawing->nr_sprites; i++)
+                               draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i, 1);
+                       uae_u16 oxor = bplxor;
+                       memset (pixdata.apixels, 0, sizeof pixdata);
+                       bplxor = 0;
+                       do_color_changes (pfield_do_fill_line, pfield_do_linetoscr, lineno);
+                       bplxor = oxor;
+
+               } else {
+
+                       playfield_start = visible_right_border;
+                       playfield_end = visible_right_border;
+                       do_color_changes (pfield_do_fill_line, pfield_do_fill_line, lineno);
+
+               }
+
+               if (dh == dh_emerg)
+                       memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
+
+               do_flush_line (vb, gfx_ypos);
+               if (do_double) {
+                       if (dh == dh_emerg)
+                               memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_bytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
+                       else if (dh == dh_buf)
+                               memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
+                       do_flush_line (vb, follow_ypos);
+               }
+
+       } else {
+
+               int tmp = hposblank;
+               hposblank = brdblank;
+               fill_line ();
+               do_flush_line (vb, gfx_ypos);
+               hposblank = tmp;
+
+       }
+}
+
+static void center_image (void)
+{
+       int prev_x_adjust = visible_left_border;
+       int prev_y_adjust = thisframe_y_adjust;
+       int tmp;
+
+       int w = gfxvidinfo.drawbuffer.inwidth;
+       if (currprefs.gfx_xcenter && !currprefs.gfx_filter_autoscale && max_diwstop > 0) {
+
+               if (max_diwstop - min_diwstart < w && currprefs.gfx_xcenter == 2)
+                       /* Try to center. */
+                       visible_left_border = (max_diwstop - min_diwstart - w) / 2 + min_diwstart;
+               else
+                       visible_left_border = max_diwstop - w - (max_diwstop - min_diwstart - w) / 2;
+               visible_left_border &= ~((xshift (1, lores_shift)) - 1);
+
+               /* Would the old value be good enough? If so, leave it as it is if we want to
+               * be clever. */
+               if (currprefs.gfx_xcenter == 2) {
+                       if (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart && min_diwstart - visible_left_border <= 32)
+                               visible_left_border = prev_x_adjust;
+               }
+       } else if (gfxvidinfo.drawbuffer.extrawidth) {
+               visible_left_border = max_diwlastword - w;
+               //visible_left_border += gfxvidinfo.drawbuffer.extrawidth << currprefs.gfx_resolution;
+       } else {
+               if (gfxvidinfo.drawbuffer.inxoffset < 0) {
+                       visible_left_border = 0;
+               } else {
+                       visible_left_border = gfxvidinfo.drawbuffer.inxoffset - DISPLAY_LEFT_SHIFT;
+               }
+       }
+
+
+       if (visible_left_border > max_diwlastword - 32)
+               visible_left_border = max_diwlastword - 32;
+       if (visible_left_border < 0)
+               visible_left_border = 0;
+       visible_left_border &= ~((xshift (1, lores_shift)) - 1);
+
+       //write_log (_T("%d %d %d %d %d\n"), max_diwlastword, gfxvidinfo.drawbuffer.width, lores_shift, currprefs.gfx_resolution, visible_left_border);
+
+       linetoscr_x_adjust_bytes = visible_left_border * gfxvidinfo.drawbuffer.pixbytes;
+
+       visible_right_border = visible_left_border + w;
+       if (visible_right_border > max_diwlastword)
+               visible_right_border = max_diwlastword;
+
+       thisframe_y_adjust = minfirstline;
+       if (currprefs.gfx_ycenter && thisframe_first_drawn_line >= 0 && !currprefs.gfx_filter_autoscale) {
+
+               if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line && currprefs.gfx_ycenter == 2)
+                       thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line) / 2 + thisframe_first_drawn_line;
+               else
+                       thisframe_y_adjust = thisframe_first_drawn_line + ((thisframe_last_drawn_line - thisframe_first_drawn_line) - max_drawn_amiga_line) / 2;
+
+               /* Would the old value be good enough? If so, leave it as it is if we want to
+               * be clever. */
+               if (currprefs.gfx_ycenter == 2) {
+                       if (thisframe_y_adjust != prev_y_adjust
+                               && prev_y_adjust <= thisframe_first_drawn_line
+                               && prev_y_adjust + max_drawn_amiga_line > thisframe_last_drawn_line)
+                               thisframe_y_adjust = prev_y_adjust;
+               }
+       }
+
+       /* Make sure the value makes sense */
+       if (thisframe_y_adjust + max_drawn_amiga_line > maxvpos_nom)
+               thisframe_y_adjust = maxvpos_nom - max_drawn_amiga_line;
+       if (thisframe_y_adjust < minfirstline)
+               thisframe_y_adjust = minfirstline;
+
+       thisframe_y_adjust_real = thisframe_y_adjust << linedbl;
+       tmp = (maxvpos_nom - thisframe_y_adjust + 1) << linedbl;
+       if (tmp != max_ypos_thisframe) {
+               last_max_ypos = tmp;
+               if (last_max_ypos < 0)
+                       last_max_ypos = 0;
+       }
+       max_ypos_thisframe = tmp;
+
+       /* @@@ interlace_seen used to be (bplcon0 & 4), but this is probably
+       * better.  */
+       if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust)
+               frame_redraw_necessary |= (interlace_seen > 0 && linedbl) ? 2 : 1;
+
+       max_diwstop = 0;
+       min_diwstart = 10000;
+
+       gfxvidinfo.drawbuffer.xoffset = (DISPLAY_LEFT_SHIFT << RES_MAX) + (visible_left_border << (RES_MAX - currprefs.gfx_resolution));
+       gfxvidinfo.drawbuffer.yoffset = thisframe_y_adjust << VRES_MAX;
+
+       visible_left_start = visible_left_border;
+       visible_right_stop = visible_left_start + gfxvidinfo.drawbuffer.inwidth;;
+}
+
+#define FRAMES_UNTIL_RES_SWITCH 1
+static int frame_res_cnt;
+static void init_drawing_frame (void)
+{
+       int i, maxline;
+#if 1
+       static int frame_res_old;
+
+       if (currprefs.gfx_autoresolution && frame_res >= 0 && frame_res_lace >= 0) {
+               if (FRAMES_UNTIL_RES_SWITCH > 0 && frame_res_old == frame_res * 2 + frame_res_lace) {
+                       frame_res_cnt--;
+                       if (frame_res_cnt == 0) {
+                               int m = frame_res * 2 + frame_res_lace;
+                               struct wh *dst = currprefs.gfx_apmode[0].gfx_fullscreen ? &changed_prefs.gfx_size_fs : &changed_prefs.gfx_size_win;
+                               while (m < 3 * 2) {
+                                       struct wh *src = currprefs.gfx_apmode[0].gfx_fullscreen ? &currprefs.gfx_size_fs_xtra[m] : &currprefs.gfx_size_win_xtra[m];
+                                       if ((src->width > 0 && src->height > 0) || (currprefs.gfx_api || currprefs.gfx_filter > 0)) {
+                                               int nr = m >> 1;
+                                               int nl = (m & 1) == 0 ? 0 : 1;
+                                               int nr_o = nr;
+                                               int nl_o = nl;
+
+                                               if (currprefs.gfx_autoresolution_minh < 0) {
+                                                       if (nr < nl)
+                                                               nr = nl;
+                                               } else if (nr < currprefs.gfx_autoresolution_minh) {
+                                                       nr = currprefs.gfx_autoresolution_minh;
+                                               }
+                                               if (currprefs.gfx_autoresolution_minv < 0) {
+                                                       if (nl < nr)
+                                                               nl = nr;
+                                               } else if (nl < currprefs.gfx_autoresolution_minv) {
+                                                       nl = currprefs.gfx_autoresolution_minv;
+                                               }
+
+                                               if (nr > gfxvidinfo.gfx_resolution_reserved)
+                                                       nr = gfxvidinfo.gfx_resolution_reserved;
+                                               if (nl > gfxvidinfo.gfx_vresolution_reserved)
+                                                       nl = gfxvidinfo.gfx_vresolution_reserved;
+
+                                               if (changed_prefs.gfx_resolution != nr || changed_prefs.gfx_vresolution != nl) {
+                                                       changed_prefs.gfx_resolution = nr;
+                                                       changed_prefs.gfx_vresolution = nl;
+                                                       write_log (_T("RES -> %d (%d) LINE -> %d (%d) (%d - %d, %d - %d)\n"), nr, nr_o, nl, nl_o,
+                                                               currprefs.gfx_autoresolution_minh, currprefs.gfx_autoresolution_minv,
+                                                               gfxvidinfo.gfx_resolution_reserved, gfxvidinfo.gfx_vresolution_reserved);
+                                                       config_changed = 1;
+                                                       //activate_debugger ();
+                                               }
+                                               if (src->width > 0 && src->height > 0) {
+                                                       if (memcmp (dst, src, sizeof *dst)) {
+                                                               *dst = *src;
+                                                               config_changed = 1;
+                                                       }
+                                               }
+                                               break;
+                                       }
+                                       m++;
+                               }
+                               frame_res_cnt = FRAMES_UNTIL_RES_SWITCH;
+                       }
+               } else {
+                       frame_res_old = frame_res * 2 + frame_res_lace;
+                       frame_res_cnt = FRAMES_UNTIL_RES_SWITCH;
+               }
+       }
+       frame_res = -1;
+       frame_res_lace = 0;
+
+       if (can_use_lores > AUTO_LORES_FRAMES && 0) {
+               lores_factor = 1;
+               lores_shift = 0;
+       } else {
+               can_use_lores++;
+               lores_reset ();
+       }
+#endif
+
+       init_hardware_for_drawing_frame ();
+
+       if (thisframe_first_drawn_line < 0)
+               thisframe_first_drawn_line = minfirstline;
+       if (thisframe_first_drawn_line > thisframe_last_drawn_line)
+               thisframe_last_drawn_line = thisframe_first_drawn_line;
+
+       maxline = ((maxvpos_nom + 1) << linedbl) + 2;
+#ifdef SMART_UPDATE
+       for (i = 0; i < maxline; i++) {
+               switch (linestate[i]) {
+               case LINE_DONE_AS_PREVIOUS:
+                       linestate[i] = LINE_REMEMBERED_AS_PREVIOUS;
+                       break;
+               case LINE_REMEMBERED_AS_BLACK:
+                       break;
+               default:
+                       linestate[i] = LINE_UNDECIDED;
+                       break;
+               }
+       }
+#else
+       memset (linestate, LINE_UNDECIDED, maxline);
+#endif
+       last_drawn_line = 0;
+       first_drawn_line = 32767;
+
+       first_block_line = last_block_line = NO_BLOCK;
+       if (frame_redraw_necessary)
+               frame_redraw_necessary--;
+
+       center_image ();
+
+       thisframe_first_drawn_line = -1;
+       thisframe_last_drawn_line = -1;
+
+       drawing_color_matches = -1;
+       seen_sprites = -1;
+}
+
+void putpixel (uae_u8 *buf, int bpp, int x, xcolnr c8, int opaq)
+{
+       if (x <= 0)
+               return;
+
+       switch (bpp) {
+       case 1:
+               buf[x] = (uae_u8)c8;
+               break;
+       case 2:
+               {
+                       uae_u16 *p = (uae_u16*)buf + x;
+                       *p = (uae_u16)c8;
+                       break;
+               }
+       case 3:
+               /* no 24 bit yet */
+               break;
+       case 4:
+               {
+                       int i;
+                       if (1 || opaq || currprefs.gfx_filter == 0) {
+                               uae_u32 *p = (uae_u32*)buf + x;
+                               *p = c8;
+                       } else {
+                               for (i = 0; i < 4; i++) {
+                                       int v1 = buf[i + bpp * x];
+                                       int v2 = (c8 >> (i * 8)) & 255;
+                                       v1 = (v1 * 2 + v2 * 3) / 5;
+                                       if (v1 > 255)
+                                               v1 = 255;
+                                       buf[i + bpp * x] = v1;
+                               }
+                       }
+                       break;
+               }
+       }
+}
+
+static void draw_status_line (int line, int statusy)
+{
+       int bpp, y;
+       uae_u8 *buf;
+
+       if (!(currprefs.leds_on_screen & STATUSLINE_CHIPSET) || (currprefs.leds_on_screen & STATUSLINE_TARGET))
+               return;
+       bpp = gfxvidinfo.drawbuffer.pixbytes;
+       y = line - (gfxvidinfo.drawbuffer.outheight - TD_TOTAL_HEIGHT);
+       xlinebuffer = gfxvidinfo.drawbuffer.linemem;
+       if (xlinebuffer == 0)
+               xlinebuffer = row_map[line];
+       buf = xlinebuffer;
+       draw_status_line_single (buf, bpp, statusy, gfxvidinfo.drawbuffer.outwidth, xredcolors, xgreencolors, xbluecolors, NULL);
+}
+
+static void draw_debug_status_line (int line)
+{
+       xlinebuffer = gfxvidinfo.drawbuffer.linemem;
+       if (xlinebuffer == 0)
+               xlinebuffer = row_map[line];
+       debug_draw_cycles (xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, line, gfxvidinfo.drawbuffer.outwidth, gfxvidinfo.drawbuffer.outheight, xredcolors, xgreencolors, xbluecolors);
+}
+
+#define LIGHTPEN_HEIGHT 12
+#define LIGHTPEN_WIDTH 17
+
+static const char *lightpen_cursor = {
+       "------.....------"
+       "------.xxx.------"
+       "------.xxx.------"
+       "------.xxx.------"
+       ".......xxx......."
+       ".xxxxxxxxxxxxxxx."
+       ".xxxxxxxxxxxxxxx."
+       ".......xxx......."
+       "------.xxx.------"
+       "------.xxx.------"
+       "------.xxx.------"
+       "------.....------"
+};
+
+static void draw_lightpen_cursor (int x, int y, int line, int onscreen)
+{
+       int i;
+       const char *p;
+       int color1 = onscreen ? 0xff0 : 0xf00;
+       int color2 = 0x000;
+
+       xlinebuffer = gfxvidinfo.drawbuffer.linemem;
+       if (xlinebuffer == 0)
+               xlinebuffer = row_map[line];
+
+       p = lightpen_cursor + y * LIGHTPEN_WIDTH;
+       for (i = 0; i < LIGHTPEN_WIDTH; i++) {
+               int xx = x + i - LIGHTPEN_WIDTH / 2;
+               if (*p != '-' && xx >= 0 && xx < gfxvidinfo.drawbuffer.outwidth)
+                       putpixel (xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, xx, *p == 'x' ? xcolors[color1] : xcolors[color2], 1);
+               p++;
+       }
+}
+
+static int lightpen_y1, lightpen_y2;
+
+static void lightpen_update (struct vidbuffer *vb)
+{
+       int i;
+
+       if (lightpen_x < LIGHTPEN_WIDTH + 1)
+               lightpen_x = LIGHTPEN_WIDTH + 1;
+       if (lightpen_x >= gfxvidinfo.drawbuffer.inwidth - LIGHTPEN_WIDTH - 1)
+               lightpen_x = gfxvidinfo.drawbuffer.inwidth - LIGHTPEN_WIDTH - 2;
+       if (lightpen_y < LIGHTPEN_HEIGHT + 1)
+               lightpen_y = LIGHTPEN_HEIGHT + 1;
+       if (lightpen_y >= gfxvidinfo.drawbuffer.inheight - LIGHTPEN_HEIGHT - 1)
+               lightpen_y = gfxvidinfo.drawbuffer.inheight - LIGHTPEN_HEIGHT - 2;
+       if (lightpen_y >= max_ypos_thisframe - LIGHTPEN_HEIGHT - 1)
+               lightpen_y = max_ypos_thisframe - LIGHTPEN_HEIGHT - 2;
+
+       lightpen_cx = (((lightpen_x + visible_left_border) >> lores_shift) >> 1) + DISPLAY_LEFT_SHIFT - DIW_DDF_OFFSET;
+
+       lightpen_cy = lightpen_y;
+       lightpen_cy >>= linedbl;
+       lightpen_cy += minfirstline;
+
+       if (lightpen_cx < 0x18)
+               lightpen_cx = 0x18;
+       if (lightpen_cx >= maxhpos)
+               lightpen_cx -= maxhpos;
+       if (lightpen_cy < minfirstline)
+               lightpen_cy = minfirstline;
+       if (lightpen_cy >= maxvpos)
+               lightpen_cy = maxvpos - 1;
+
+       for (i = 0; i < LIGHTPEN_HEIGHT; i++) {
+               int line = lightpen_y + i - LIGHTPEN_HEIGHT / 2;
+               if (line >= 0 || line < max_ypos_thisframe) {
+                       draw_lightpen_cursor(lightpen_x, i, line, lightpen_cx > 0);
+                       flush_line (vb, line);
+               }
+       }
+       lightpen_y1 = lightpen_y - LIGHTPEN_HEIGHT / 2 - 1 + min_ypos_for_screen;
+       lightpen_y2 = lightpen_y1 + LIGHTPEN_HEIGHT + 2;
+}
+
+void finish_drawing_frame (void)
+{
+       int i;
+       bool didflush = false;
+       struct vidbuffer *vb = &gfxvidinfo.drawbuffer;
+
+       gfxvidinfo.outbuffer = vb;
+
+       if (! lockscr (vb, false)) {
+               notice_screen_contents_lost ();
+               return;
+       }
+
+#ifndef SMART_UPDATE
+       /* @@@ This isn't exactly right yet. FIXME */
+       if (!interlace_seen)
+               do_flush_screen (first_drawn_line, last_drawn_line);
+       else
+               unlockscr ();
+       return;
+#endif
+
+       for (i = 0; i < max_ypos_thisframe; i++) {
+               int i1 = i + min_ypos_for_screen;
+               int line = i + thisframe_y_adjust_real;
+               int where2;
+
+               where2 = amiga2aspect_line_map[i1];
+               if (where2 >= vb->inheight)
+                       break;
+               if (where2 < 0)
+                       continue;
+               hposblank = 0;
+               pfield_draw_line (vb, line, where2, amiga2aspect_line_map[i1 + 1]);
+       }
+
+       /* clear possible old garbage at the bottom if emulated area become smaller */
+       for (i = last_max_ypos; i < vb->outheight; i++) {
+               int i1 = i + min_ypos_for_screen;
+               int line = i + thisframe_y_adjust_real;
+               int where2 = amiga2aspect_line_map[i1];
+
+               if (where2 >= gfxvidinfo.drawbuffer.outheight)
+                       break;
+               if (where2 < 0)
+                       continue;
+
+               hposblank = i > last_max_ypos ;// + AMIGA_HEIGHT_EXTRA;
+
+               xlinebuffer = vb->linemem;
+               if (xlinebuffer == 0)
+                       xlinebuffer = row_map[where2];
+               xlinebuffer -= linetoscr_x_adjust_bytes;
+               fill_line ();
+               if (line < max_ypos_thisframe)
+                       linestate[line] = LINE_UNDECIDED;
+               do_flush_line (vb, where2);
+       }
+
+       if (currprefs.leds_on_screen) {
+               int slx, sly;
+               statusline_getpos (&slx, &sly, vb->outwidth, vb->outheight);
+               for (i = 0; i < TD_TOTAL_HEIGHT; i++) {
+                       int line = sly + i;
+                       draw_status_line (line, i);
+                       do_flush_line (vb, line);
+               }
+       }
+       if (debug_dma > 1) {
+               for (i = 0; i < vb->outheight; i++) {
+                       int line = i;
+                       draw_debug_status_line (line);
+                       do_flush_line (vb, line);
+               }
+       }
+
+       if (lightpen_x > 0 || lightpen_y > 0)
+               lightpen_update (vb);
+
+       if (currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated) {
+               static bool specialon;
+               if (emulate_specialmonitors (vb, &gfxvidinfo.tempbuffer)) {
+                       vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer;
+                       if (vb->nativepositioning) {
+                               vb->inwidth = gfxvidinfo.drawbuffer.inwidth;
+                               vb->inheight = gfxvidinfo.drawbuffer.inheight;
+                               vb->inwidth2 = gfxvidinfo.drawbuffer.inwidth2;
+                               vb->inheight2 = gfxvidinfo.drawbuffer.inheight2;
+                               vb->outwidth = gfxvidinfo.drawbuffer.outwidth;
+                               vb->outheight = gfxvidinfo.drawbuffer.outheight;
+                       }
+                       gfxvidinfo.drawbuffer.tempbufferinuse = true;
+                       if (!specialon)
+                               compute_framesync ();
+                       specialon = true;
+                       do_flush_screen (vb, 0, vb->outheight);
+                       didflush = true;
+               } else {
+                       gfxvidinfo.drawbuffer.tempbufferinuse = false;
+                       if (specialon)
+                               compute_framesync ();
+                       specialon = false;
+               }
+       }
+
+       if (!didflush)
+               do_flush_screen (vb, first_drawn_line, last_drawn_line);
+
+
+#ifdef ECS_DENISE
+       if (brdblank_changed) {
+               last_max_ypos = max_ypos_thisframe;
+               for (i = 0; i < sizeof linestate / sizeof *linestate; i++)
+                       linestate[i] = LINE_UNDECIDED;
+               notice_screen_contents_lost ();
+               brdblank_changed = false;
+       }
+#endif
+}
+
+void hardware_line_completed (int lineno)
+{
+#ifndef SMART_UPDATE
+       {
+               int i, where;
+               /* l is the line that has been finished for drawing. */
+               i = lineno - thisframe_y_adjust_real;
+               if (i >= 0 && i < max_ypos_thisframe) {
+                       where = amiga2aspect_line_map[i+min_ypos_for_screen];
+                       if (where < gfxvidinfo.drawbuffer.outheight && where >= 0)
+                               pfield_draw_line (lineno, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]);
+               }
+       }
+#endif
+}
+
+void check_picasso (void)
+{
+#ifdef PICASSO96
+       if (picasso_on && picasso_redraw_necessary)
+               picasso_refresh ();
+       picasso_redraw_necessary = 0;
+
+       if (picasso_requested_on == picasso_on)
+               return;
+
+       picasso_on = picasso_requested_on;
+
+       if (!picasso_on)
+               clear_inhibit_frame (IHF_PICASSO);
+       else
+               set_inhibit_frame (IHF_PICASSO);
+
+       gfx_set_picasso_state (picasso_on);
+       picasso_enablescreen (picasso_requested_on);
+
+       notice_screen_contents_lost ();
+       notice_new_xcolors ();
+       count_frame ();
+#endif
+}
+
+void redraw_frame (void)
+{
+       last_drawn_line = 0;
+       first_drawn_line = 32767;
+       finish_drawing_frame ();
+       flush_screen (gfxvidinfo.inbuffer, 0, 0);
+}
+
+void vsync_handle_check (void)
+{
+       check_picasso ();
+
+       int changed = check_prefs_changed_gfx ();
+       if (changed > 0) {
+               reset_drawing ();
+               init_row_map ();
+               init_aspect_maps ();
+               notice_screen_contents_lost ();
+               notice_new_xcolors ();
+       } else if (changed < 0) {
+               reset_drawing ();
+               init_row_map ();
+               init_aspect_maps ();
+               notice_screen_contents_lost ();
+               notice_new_xcolors ();
+       }
+       check_prefs_changed_audio ();
+       check_prefs_changed_custom ();
+       check_prefs_changed_cpu ();
+}
+
+void vsync_handle_redraw (int long_frame, int lof_changed, uae_u16 bplcon0p, uae_u16 bplcon3p)
+{
+       last_redraw_point++;
+       if (lof_changed || interlace_seen <= 0 || last_redraw_point >= 2 || long_frame || doublescan < 0) {
+               last_redraw_point = 0;
+
+               if (framecnt == 0)
+                       finish_drawing_frame ();
+#if 0
+               if (interlace_seen > 0) {
+                       interlace_seen = -1;
+               } else if (interlace_seen == -1) {
+                       interlace_seen = 0;
+                       if (currprefs.gfx_scandoubler && currprefs.gfx_vresolution)
+                               notice_screen_contents_lost ();
+               }
+#endif
+
+               if (quit_program < 0) {
+#ifdef SAVESTATE
+                       if (!savestate_state) {
+                               if (currprefs.quitstatefile[0]) {
+                                       savestate_initsave (currprefs.quitstatefile, 1, 1, true); 
+                                       save_state (currprefs.quitstatefile, _T(""));
+                               }
+                       }
+#endif
+                       quit_program = -quit_program;
+                       set_inhibit_frame (IHF_QUIT_PROGRAM);
+                       set_special (SPCFLAG_BRK);
+                       return;
+               }
+
+               count_frame ();
+
+               if (framecnt == 0)
+                       init_drawing_frame ();
+               else if (currprefs.cpu_cycle_exact)
+                       init_hardware_for_drawing_frame ();
+       } else {
+               if (isvsync_chipset ())
+                       flush_screen (gfxvidinfo.inbuffer, 0, 0); /* vsync mode */
+       }
+
+       /* check borderblank here because bplcon0 or especially bplcon3 may only be written once outside of displayable area */
+       bplcon0_store = bplcon0p;
+       bplcon3_store = bplcon3p;
+       isbrdblank ();
+
+       gui_flicker_led (-1, 0, 0);
+#ifdef AVIOUTPUT
+       frame_drawn ();
+#endif
+}
+
+void hsync_record_line_state (int lineno, enum nln_how how, int changed)
+{
+       uae_u8 *state;
+
+       if (framecnt != 0)
+               return;
+
+       state = linestate + lineno;
+       changed += frame_redraw_necessary + ((lineno >= lightpen_y1 && lineno <= lightpen_y2) ? 1 : 0);
+
+       switch (how) {
+       case nln_normal:
+               *state = changed ? LINE_DECIDED : LINE_DONE;
+               break;
+       case nln_doubled:
+               *state = changed ? LINE_DECIDED_DOUBLE : LINE_DONE;
+               changed += state[1] != LINE_REMEMBERED_AS_PREVIOUS;
+               state[1] = changed ? LINE_AS_PREVIOUS : LINE_DONE_AS_PREVIOUS;
+               break;
+       case nln_nblack:
+               *state = changed ? LINE_DECIDED : LINE_DONE;
+               if (state[1] != LINE_REMEMBERED_AS_BLACK)
+                       state[1] = LINE_BLACK;
+               break;
+       case nln_lower:
+               if (state[-1] == LINE_UNDECIDED)
+                       state[-1] = LINE_DECIDED; //LINE_BLACK;
+               *state = changed ? LINE_DECIDED : LINE_DONE;
+               break;
+       case nln_upper:
+               *state = changed ? LINE_DECIDED : LINE_DONE;
+               if (state[1] == LINE_UNDECIDED
+                       || state[1] == LINE_REMEMBERED_AS_PREVIOUS
+                       || state[1] == LINE_AS_PREVIOUS)
+                       state[1] = LINE_DECIDED; //LINE_BLACK;
+               break;
+       }
+}
+
+static void dummy_flush_line (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int line_no)
+{
+}
+
+static void dummy_flush_block (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int first_line, int last_line)
+{
+}
+
+static void dummy_flush_screen (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int first_line, int last_line)
+{
+}
+
+static void dummy_flush_clear_screen (struct vidbuf_description *gfxinfo, struct vidbuffer *vb)
+{
+}
+
+static int  dummy_lock (struct vidbuf_description *gfxinfo, struct vidbuffer *vb)
+{
+       return 1;
+}
+
+static void dummy_unlock (struct vidbuf_description *gfxinfo, struct vidbuffer *vb)
+{
+}
+
+static void gfxbuffer_reset (void)
+{
+       gfxvidinfo.drawbuffer.flush_line         = dummy_flush_line;
+       gfxvidinfo.drawbuffer.flush_block        = dummy_flush_block;
+       gfxvidinfo.drawbuffer.flush_screen       = dummy_flush_screen;
+       gfxvidinfo.drawbuffer.flush_clear_screen = dummy_flush_clear_screen;
+       gfxvidinfo.drawbuffer.lockscr            = dummy_lock;
+       gfxvidinfo.drawbuffer.unlockscr          = dummy_unlock;
+}
+
+void notice_resolution_seen (int res, bool lace)
+{
+       if (res > frame_res)
+               frame_res = res;
+       if (res > 0)
+               can_use_lores = 0;
+       if (!frame_res_lace && lace)
+               frame_res_lace = lace;
+}
+
+bool notice_interlace_seen (bool lace)
+{
+       bool changed = false;
+       // non-lace to lace switch (non-lace active at least one frame)?
+       if (lace) {
+               if (interlace_seen == 0) {
+                       changed = true;
+                       //write_log (_T("->lace PC=%x\n"), m68k_getpc ());
+               }
+               interlace_seen = currprefs.gfx_vresolution ? 1 : -1;
+       } else {
+               if (interlace_seen) {
+                       changed = true;
+                       //write_log (_T("->non-lace PC=%x\n"), m68k_getpc ());
+               }
+               interlace_seen = 0;
+       }
+       return changed;
+}
+
+static void clearbuffer (struct vidbuffer *dst)
+{
+       if (!dst->bufmem_allocated)
+               return;
+       uae_u8 *p = dst->bufmem_allocated;
+       for (int y = 0; y < dst->height_allocated; y++) {
+               memset (p, 0, dst->width_allocated * dst->pixbytes);
+               p += dst->rowbytes;
+       }
+}
+
+void reset_decision_table (void)
+{
+       for (int i = 0; i < sizeof linestate / sizeof *linestate; i++)
+               linestate[i] = LINE_UNDECIDED;
+}
+
+void reset_drawing (void)
+{
+       unsigned int i;
+
+       max_diwstop = 0;
+
+       lores_reset ();
+
+       for (i = 0; i < sizeof linestate / sizeof *linestate; i++)
+               linestate[i] = LINE_UNDECIDED;
+
+       init_aspect_maps ();
+
+       init_row_map ();
+
+       last_redraw_point = 0;
+
+       memset (spixels, 0, sizeof spixels);
+       memset (&spixstate, 0, sizeof spixstate);
+
+       init_drawing_frame ();
+
+       notice_screen_contents_lost ();
+       frame_res_cnt = FRAMES_UNTIL_RES_SWITCH;
+       lightpen_y1 = lightpen_y2 = -1;
+
+       reset_custom_limits ();
+
+       clearbuffer (&gfxvidinfo.drawbuffer);
+       clearbuffer (&gfxvidinfo.tempbuffer);
+}
+
+void drawing_init (void)
+{
+       gen_pfield_tables ();
+
+       uae_sem_init (&gui_sem, 0, 1);
+#ifdef PICASSO96
+       if (!isrestore ()) {
+               picasso_on = 0;
+               picasso_requested_on = 0;
+               gfx_set_picasso_state (0);
+       }
+#endif
+       xlinebuffer = gfxvidinfo.drawbuffer.bufmem;
+
+       inhibit_frame = 0;
+
+       gfxbuffer_reset ();
+       reset_drawing ();
+}
+
+int isvsync_chipset (void)
+{
+       if (picasso_on || !currprefs.gfx_apmode[0].gfx_vsync || (currprefs.gfx_apmode[0].gfx_vsync == 0 && !currprefs.gfx_apmode[0].gfx_fullscreen))
+               return 0;
+       if (currprefs.gfx_apmode[0].gfx_vsyncmode == 0)
+               return 1;
+       if (currprefs.m68k_speed >= 0)
+               return -1;
+       return currprefs.cachesize ? -3 : -2;
+}
+
+int isvsync_rtg (void)
+{
+       if (!picasso_on || !currprefs.gfx_apmode[1].gfx_vsync || (currprefs.gfx_apmode[1].gfx_vsync == 0 && !currprefs.gfx_apmode[1].gfx_fullscreen))
+               return 0;
+       if (currprefs.gfx_apmode[1].gfx_vsyncmode == 0)
+               return 1;
+       if (currprefs.m68k_speed >= 0)
+               return -1;
+       return currprefs.cachesize ? -3 : -2;
+}
+
+int isvsync (void)
+{
+       if (picasso_on)
+               return isvsync_rtg ();
+       else
+               return isvsync_chipset ();
+}
index ff2b48dac931ce2aac3428204fcf275af7ba6274..5636a763903309efcc0bfceaf3bbc042d6aaae0c 100644 (file)
@@ -50,7 +50,7 @@ happening, all ports should restrict window widths to be multiples of 16 pixels.
 #include "inputdevice.h"
 #include "debug.h"
 
-extern bool emulate_specialmonitors(struct vidbuffer*, struct vidbuffer*);
+extern bool emulate_specialmonitors (struct vidbuffer*, struct vidbuffer*);
 
 extern int sprite_buffer_res;
 int lores_factor, lores_shift;
@@ -565,8 +565,8 @@ void get_custom_mouse_limits (int *pw, int *ph, int *pdx, int *pdy, int dbl)
 
        delay1 = (firstword_bplcon1 & 0x0f) | ((firstword_bplcon1 & 0x0c00) >> 6);
        delay2 = ((firstword_bplcon1 >> 4) & 0x0f) | (((firstword_bplcon1 >> 4) & 0x0c00) >> 6);
-       if (delay1 == delay2)
-               ;//dx += delay1;
+//     if (delay1 == delay2)
+//             dx += delay1;
 
        dx = xshift (dx, res_shift);
 
@@ -2396,13 +2396,10 @@ static void center_image (void)
                frame_redraw_necessary |= (interlace_seen > 0 && linedbl) ? 2 : 1;
 
        max_diwstop = 0;
-       min_diwstart = 10000;
+       min_diwstart = MAX_STOP;
 
        gfxvidinfo.drawbuffer.xoffset = (DISPLAY_LEFT_SHIFT << RES_MAX) + (visible_left_border << (RES_MAX - currprefs.gfx_resolution));
        gfxvidinfo.drawbuffer.yoffset = thisframe_y_adjust << VRES_MAX;
-
-       visible_left_start = visible_left_border;
-       visible_right_stop = visible_left_start + gfxvidinfo.drawbuffer.inwidth;;
 }
 
 #define FRAMES_UNTIL_RES_SWITCH 1
index 1c708c24953137b0a5ed65b8a76d13a85636c3ed..4fc6e6a5c2c20aa43365b8f4417b66428d6a9aa9 100644 (file)
@@ -413,6 +413,26 @@ static uae_u32 vhd_checksum (uae_u8 *p, int offset)
        return ~sum;
 }
 
+static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
+static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len);
+
+static void hdf_init_cache (struct hardfiledata *hfd)
+{
+}
+static void hdf_flush_cache (struct hardfiledata *hdf)
+{
+}
+
+static int hdf_cache_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
+{
+       return hdf_read2 (hfd, buffer, offset, len);
+}
+
+static int hdf_cache_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
+{
+       return hdf_write2 (hfd, buffer, offset, len);
+}
+
 int hdf_open (struct hardfiledata *hfd, const TCHAR *pname)
 {
        uae_u8 tmp[512], tmp2[512];
@@ -472,6 +492,7 @@ int hdf_open (struct hardfiledata *hfd, const TCHAR *pname)
        write_log (_T("HDF is VHD %s image, virtual size=%dK\n"),
                hfd->vhd_type == 2 ? _T("fixed") : _T("dynamic"),
                hfd->virtsize / 1024);
+       hdf_init_cache (hfd);
        return 1;
 nonvhd:
        hfd->vhd_type = 0;
@@ -483,6 +504,7 @@ end:
 
 void hdf_close (struct hardfiledata *hfd)
 {
+       hdf_flush_cache (hfd);
        hdf_close_target (hfd);
        hfd->vhd_type = 0;
        xfree (hfd->vhd_header);
@@ -792,6 +814,16 @@ static int hdf_read2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, in
                return hdf_read_target (hfd, buffer, offset, len);
 }
 
+static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
+{
+       if (hfd->vhd_type == VHD_DYNAMIC)
+               return vhd_write (hfd, buffer, offset, len);
+       else if (hfd->vhd_type == VHD_FIXED)
+               return hdf_write_target (hfd, buffer, offset + 512, len);
+       else
+               return hdf_write_target (hfd, buffer, offset, len);
+}
+
 static void adide_decode (void *v, int len)
 {
        int i;
@@ -938,10 +970,10 @@ int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
        int v;
 
        if (!hfd->adide) {
-               v = hdf_read2 (hfd, buffer, offset, len);
+               v = hdf_cache_read (hfd, buffer, offset, len);
        } else {
                offset += 512;
-               v = hdf_read2 (hfd, buffer, offset, len);
+               v = hdf_cache_read (hfd, buffer, offset, len);
                adide_decode (buffer, len);
        }
        if (hfd->byteswap)
@@ -949,16 +981,6 @@ int hdf_read (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
        return v;
 }
 
-static int hdf_write2 (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
-{
-       if (hfd->vhd_type == VHD_DYNAMIC)
-               return vhd_write (hfd, buffer, offset, len);
-       else if (hfd->vhd_type == VHD_FIXED)
-               return hdf_write_target (hfd, buffer, offset + 512, len);
-       else
-               return hdf_write_target (hfd, buffer, offset, len);
-}
-
 int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
 {
        int v;
@@ -966,11 +988,11 @@ int hdf_write (struct hardfiledata *hfd, void *buffer, uae_u64 offset, int len)
        if (hfd->byteswap)
                hdf_byteswap (buffer, len);
        if (!hfd->adide) {
-               v = hdf_write2 (hfd, buffer, offset, len);
+               v = hdf_cache_write (hfd, buffer, offset, len);
        } else {
                offset += 512;
                adide_encode (buffer, len);
-               v = hdf_write2 (hfd, buffer, offset, len);
+               v = hdf_cache_write (hfd, buffer, offset, len);
                adide_decode (buffer, len);
        }
        if (hfd->byteswap)
index a01289c1f812b417f2a8136ea1b1b82e56d9ea75..e33af5a5463c09d77a2bef5f951a6fb3aac2f3cb 100644 (file)
@@ -8,6 +8,18 @@
 
 struct hardfilehandle;
 
+#define MAX_HDF_CACHE_BLOCKS 128
+struct hdf_cache
+{
+       bool valid;
+       uae_u8 *data;
+       uae_u64 block;
+       bool dirty;
+       int readcount;
+       int writecount;
+       time_t lastaccess;
+};
+
 struct hardfiledata {
     uae_u64 virtsize; // virtual size
     uae_u64 physsize; // physical size (dynamic disk)
@@ -51,6 +63,8 @@ struct hardfiledata {
 
     int drive_empty;
     TCHAR *emptyname;
+
+       struct hdf_cache bcache[MAX_HDF_CACHE_BLOCKS];
 };
 
 #define HFD_FLAGS_REALDRIVE 1
index 653e12c7b698d872fe72924e788f09de67f43d43..75f6865fe1bc0c3b530340aaf7121bcc7bd5eb7d 100644 (file)
@@ -55,7 +55,7 @@ extern int pause_emulation;
 struct uae_input_device_default_node
 {
        int evt;
-       int flags;
+       uae_u64 flags;
 };
 
 struct uae_input_device_kbr_default {
@@ -84,19 +84,22 @@ struct inputevent {
 #define ID_FLAG_GAMEPORTSCUSTOM_MASK (ID_FLAG_GAMEPORTSCUSTOM1 | ID_FLAG_GAMEPORTSCUSTOM2)
 #define ID_FLAG_AUTOFIRE_MASK (ID_FLAG_TOGGLE | ID_FLAG_INVERTTOGGLE | ID_FLAG_AUTOFIRE)
 
-#define ID_FLAG_QUALIFIER1 0x00010000
-#define ID_FLAG_QUALIFIER2 0x00020000
-#define ID_FLAG_QUALIFIER3 0x00040000
-#define ID_FLAG_QUALIFIER4 0x00080000
-#define ID_FLAG_QUALIFIER5 0x00100000
-#define ID_FLAG_QUALIFIER6 0x00200000
-#define ID_FLAG_QUALIFIER7 0x00400000
-#define ID_FLAG_QUALIFIER8 0x00800000
-#define ID_FLAG_QUALIFIER_SPECIAL 0x01000000
-#define ID_FLAG_QUALIFIER_SHIFT 0x02000000
-#define ID_FLAG_QUALIFIER_CONTROL 0x04000000
-#define ID_FLAG_QUALIFIER_ALT 0x08000000
-#define ID_FLAG_QUALIFIER_MASK 0x0fff0000
+#define ID_FLAG_QUALIFIER1          0x00000100000000
+#define ID_FLAG_QUALIFIER1_R        0x00000200000000
+#define ID_FLAG_QUALIFIER2          0x00000400000000
+#define ID_FLAG_QUALIFIER3          0x00001000000000
+#define ID_FLAG_QUALIFIER4          0x00004000000000
+#define ID_FLAG_QUALIFIER5          0x00010000000000
+#define ID_FLAG_QUALIFIER6          0x00040000000000
+#define ID_FLAG_QUALIFIER7          0x00100000000000
+#define ID_FLAG_QUALIFIER8          0x00400000000000
+#define ID_FLAG_QUALIFIER_SPECIAL   0x01000000000000
+#define ID_FLAG_QUALIFIER_SPECIAL_R 0x02000000000000
+#define ID_FLAG_QUALIFIER_SHIFT     0x04000000000000
+#define ID_FLAG_QUALIFIER_CONTROL   0x10000000000000
+#define ID_FLAG_QUALIFIER_ALT       0x40000000000000
+#define ID_FLAG_QUALIFIER_MASK      0xffffff00000000
+#define ID_FLAG_QUALIFIER_MASK_R    0xaaaaaa00000000
 
 #define IDEV_WIDGET_NONE 0
 #define IDEV_WIDGET_BUTTON 1
@@ -110,19 +113,19 @@ struct inputevent {
 #define IDEV_MAPPED_INVERTTOGGLE 8
 #define IDEV_MAPPED_GAMEPORTSCUSTOM1 16
 #define IDEV_MAPPED_GAMEPORTSCUSTOM2 32
-#define IDEV_MAPPED_QUALIFIER1 0x00010000
-#define IDEV_MAPPED_QUALIFIER2 0x00020000
-#define IDEV_MAPPED_QUALIFIER3 0x00040000
-#define IDEV_MAPPED_QUALIFIER4 0x00080000
-#define IDEV_MAPPED_QUALIFIER5 0x00100000
-#define IDEV_MAPPED_QUALIFIER6 0x00200000
-#define IDEV_MAPPED_QUALIFIER7 0x00400000
-#define IDEV_MAPPED_QUALIFIER8 0x00800000
-#define IDEV_MAPPED_QUALIFIER_SPECIAL 0x01000000
-#define IDEV_MAPPED_QUALIFIER_SHIFT 0x02000000
-#define IDEV_MAPPED_QUALIFIER_CONTROL 0x04000000
-#define IDEV_MAPPED_QUALIFIER_ALT 0x08000000
-#define IDEV_MAPPED_QUALIFIER_MASK 0x0fff0000
+#define IDEV_MAPPED_QUALIFIER1          0x00000100000000
+#define IDEV_MAPPED_QUALIFIER2          0x00000400000000
+#define IDEV_MAPPED_QUALIFIER3          0x00001000000000
+#define IDEV_MAPPED_QUALIFIER4          0x00004000000000
+#define IDEV_MAPPED_QUALIFIER5          0x00010000000000
+#define IDEV_MAPPED_QUALIFIER6          0x00040000000000
+#define IDEV_MAPPED_QUALIFIER7          0x00100000000000
+#define IDEV_MAPPED_QUALIFIER8          0x00400000000000
+#define IDEV_MAPPED_QUALIFIER_SPECIAL   0x01000000000000
+#define IDEV_MAPPED_QUALIFIER_SHIFT     0x04000000000000
+#define IDEV_MAPPED_QUALIFIER_CONTROL   0x10000000000000
+#define IDEV_MAPPED_QUALIFIER_ALT       0x40000000000000
+#define IDEV_MAPPED_QUALIFIER_MASK      0xffffff00000000
 
 #define ID_BUTTON_OFFSET 0
 #define ID_BUTTON_TOTAL 32
@@ -130,9 +133,9 @@ struct inputevent {
 #define ID_AXIS_TOTAL 32
 
 extern int inputdevice_iterate (int devnum, int num, TCHAR *name, int *af);
-extern bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, int flags, int port);
-extern int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, int flags, int port, int sub);
-extern int inputdevice_get_mapping (int devnum, int num, int *pflags, int *port, TCHAR *name, TCHAR *custom, int sub);
+extern bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, uae_u64 flags, int port);
+extern int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, uae_u64 flags, int port, int sub);
+extern int inputdevice_get_mapping (int devnum, int num, uae_u64 *pflags, int *port, TCHAR *name, TCHAR *custom, int sub);
 extern void inputdevice_copyconfig (const struct uae_prefs *src, struct uae_prefs *dst);
 extern void inputdevice_copy_single_config (struct uae_prefs *p, int src, int dst, int devnum, int selectedwidget);
 extern void inputdevice_swap_ports (struct uae_prefs *p, int devnum);
@@ -253,7 +256,7 @@ extern void inputdevice_tablet (int x, int y, int z,
 extern void inputdevice_tablet_info (int maxx, int maxy, int maxz, int maxax, int maxay, int maxaz, int xres, int yres);
 extern void inputdevice_tablet_strobe (void);
 
-extern int input_getqualifiers (void);
+extern uae_u64 input_getqualifiers (void);
 
 extern void setsystime (void);
 
index 9c348c9f8c48c4cf05ec53042f5d756c064ab049..65a5c3205c86de4a7134c253979389000a8bfa1d 100644 (file)
@@ -48,7 +48,7 @@ struct uae_input_device {
        TCHAR *configname;
        uae_s16 eventid[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL];
        TCHAR *custom[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL];
-       uae_u32 flags[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL];
+       uae_u64 flags[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL];
        uae_s8 port[MAX_INPUT_DEVICE_EVENTS][MAX_INPUT_SUB_EVENT_ALL];
        uae_s16 extra[MAX_INPUT_DEVICE_EVENTS];
        uae_s8 enabled;
@@ -296,7 +296,7 @@ struct uae_prefs {
        int gfx_filter_autoscale;
 
        bool immediate_blits;
-       bool waiting_blits;
+       int waiting_blits;
        unsigned int chipset_mask;
        bool ntscmode;
        bool genlock;
index 16d1c70b9839b3bf1e665490e3ffcaee1c7405b6..6c7821f34dbb85a206cfd5ce182f8d40eb1dfe24 100644 (file)
@@ -68,7 +68,7 @@ int inputdevice_logging = 0;
 #define ID_FLAG_CUSTOMEVENT_TOGGLED1 0x4000
 #define ID_FLAG_CUSTOMEVENT_TOGGLED2 0x8000
 
-#define ID_FLAG_SAVE_MASK_CONFIG 0xff
+#define ID_FLAG_SAVE_MASK_CONFIG 0x000000ff
 #define ID_FLAG_SAVE_MASK_QUALIFIERS ID_FLAG_QUALIFIER_MASK
 #define ID_FLAG_SAVE_MASK_FULL (ID_FLAG_SAVE_MASK_CONFIG | ID_FLAG_SAVE_MASK_QUALIFIERS)
 
@@ -116,7 +116,8 @@ struct uae_input_device2 {
 static struct uae_input_device2 joysticks2[MAX_INPUT_DEVICES];
 static struct uae_input_device2 mice2[MAX_INPUT_DEVICES];
 static uae_u8 scancodeused[MAX_INPUT_DEVICES][256];
-static int qualifiers;
+static uae_u64 qualifiers, qualifiers_r;
+static uae_s16 *qualifiers_evt[MAX_INPUT_QUALIFIERS];
 
 // fire/left mouse button pullup resistors enabled?
 static bool mouse_pullup = true;
@@ -345,7 +346,7 @@ static bool write_config_head (struct zfile *f, int idnum, int devnum, TCHAR *na
 static bool write_slot (TCHAR *p, struct uae_input_device *uid, int i, int j)
 {
        bool ok = false;
-       int flags = uid->flags[i][j];
+       uae_u64 flags = uid->flags[i][j];
        if (uid->custom[i][j] && _tcslen (uid->custom[i][j]) > 0) {
                _stprintf (p, _T("'%s'.%d"), uid->custom[i][j], flags & ID_FLAG_SAVE_MASK_CONFIG);
                ok = true;
@@ -358,9 +359,12 @@ static bool write_slot (TCHAR *p, struct uae_input_device *uid, int i, int j)
        if (ok && (flags & ID_FLAG_SAVE_MASK_QUALIFIERS)) {
                TCHAR *p2 = p + _tcslen (p);
                *p2++ = '.';
-               for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
+               for (int i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) {
                        if ((ID_FLAG_QUALIFIER1 << i) & flags) {
-                               _stprintf (p2, _T("%c"), 'A' + i);
+                               if (i & 1)
+                                       _stprintf (p2, _T("%c"), 'a' + i / 2);
+                               else
+                                       _stprintf (p2, _T("%c"), 'A' + i / 2);
                                p2++;
                        }
                }
@@ -580,13 +584,23 @@ void write_inputdevice_config (struct uae_prefs *p, struct zfile *f)
        }
 }
 
-static int getqual (const TCHAR **pp)
+static uae_u64 getqual (const TCHAR **pp)
 {
        const TCHAR *p = *pp;
-       int mask = 0;
+       uae_u64 mask = 0;
+
+       while ((*p >= 'A' && *p <= 'Z') || (*p >= 'a' && *p <= 'z')) {
+               bool press = (*p >= 'A' && *p <= 'Z');
+               int shift, inc;
 
-       while (*p >= 'A' && *p <= 'Z') {
-               mask |= ID_FLAG_QUALIFIER1 << (*p - 'A');
+               if (press) {
+                       shift = *p - 'A';
+                       inc = 0;
+               } else {
+                       shift = *p - 'a';
+                       inc = 1;
+               }
+               mask |= ID_FLAG_QUALIFIER1 << (shift * 2 + inc);
                p++;
        }
        while (*p != 0 && *p !='.' && *p != ',')
@@ -747,7 +761,7 @@ static void inputdevice_default_kb_all (struct uae_prefs *p)
                inputdevice_default_kb (p, i);
 }
 
-static bool read_slot (TCHAR *parm, int num, int joystick, int button, struct uae_input_device *id, int keynum, int subnum, struct inputevent *ie, int flags, int port, TCHAR *custom)
+static bool read_slot (TCHAR *parm, int num, int joystick, int button, struct uae_input_device *id, int keynum, int subnum, struct inputevent *ie, uae_u64 flags, int port, TCHAR *custom)
 {
        int mask;
 
@@ -989,7 +1003,8 @@ void read_inputdevice_config (struct uae_prefs *pr, const TCHAR *option, TCHAR *
 
        custom = NULL;
        for (subnum = 0; subnum < MAX_INPUT_SUB_EVENT; subnum++) {
-               int flags, port;
+               uae_u64 flags;
+               int port;
                xfree (custom);
                custom = NULL;
                p2 = getstring (&p);
@@ -1001,7 +1016,7 @@ void read_inputdevice_config (struct uae_prefs *pr, const TCHAR *option, TCHAR *
                if (p[-1] == '.')
                        flags = getnum (&p) & ID_FLAG_SAVE_MASK_CONFIG;
                if (p[-1] == '.') {
-                       if (p[0] >= 'A' && p[0] <= 'Z')
+                       if ((p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z'))
                                flags |= getqual (&p);
                        if (p[-1] == '.')
                                port = getnum (&p) + 1;
@@ -1014,7 +1029,7 @@ void read_inputdevice_config (struct uae_prefs *pr, const TCHAR *option, TCHAR *
                                int flags2 = 0;
                                if (p[-1] == '.')
                                        flags2 = getnum (&p) & ID_FLAG_SAVE_MASK_CONFIG;
-                               if (p[-1] == '.' && p[0] >= 'A' && p[0] <= 'Z')
+                               if (p[-1] == '.' && (p[0] >= 'A' && p[0] <= 'Z') || (p[0] >= 'a' && p[0] <= 'z'))
                                        flags |= getqual (&p);
                                TCHAR *custom2 = NULL;
                                struct inputevent *ie2 = readevent (p2, &custom2);
@@ -1834,6 +1849,11 @@ static void joymousecounter (int joy)
        else if (cnty == 0 && ocnty == 3)
                mouse_y[joy] += 4;
        mouse_y[joy] = (mouse_y[joy] & 0xfc) | cnty;
+
+       if (!left || !right || !top || !bot) {
+               mouse_frame_x[joy] = mouse_x[joy];
+               mouse_frame_y[joy] = mouse_y[joy];
+       }
 }
 
 static uae_u16 getjoystate (int joy)
@@ -2756,11 +2776,19 @@ end:
        }
 }
 
-static int isqual (int evt)
+static int getqualid (int evt)
 {
        if (evt > INPUTEVENT_SPC_QUALIFIER_START && evt < INPUTEVENT_SPC_QUALIFIER_END)
-               return ID_FLAG_QUALIFIER1 << (evt - INPUTEVENT_SPC_QUALIFIER1);
-       return 0;
+               return evt - INPUTEVENT_SPC_QUALIFIER1;
+       return -1;
+}
+
+static uae_u64 isqual (int evt)
+{
+       int num = getqualid (evt);
+       if (num < 0)
+               return 0;
+       return ID_FLAG_QUALIFIER1 << (num * 2);
 }
 
 static int handle_input_event (int nr, int state, int max, int autofire, bool canstopplayback, bool playbackevent)
@@ -2794,7 +2822,7 @@ static int handle_input_event (int nr, int state, int max, int autofire, bool ca
        }
 
        if ((inputdevice_logging & 1) || input_record || input_play)
-               write_log (_T("STATE=%05d MAX=%05d AF=%d QUAL=%08x '%s' \n"), state, max, autofire, qualifiers, ie->name);
+               write_log (_T("STATE=%05d MAX=%05d AF=%d QUAL=%06x '%s' \n"), state, max, autofire, (uae_u32)(qualifiers >> 32), ie->name);
        if (autofire) {
                if (state)
                        queue_input_event (nr, NULL, state, max, currprefs.input_autofire_linecnt, 1);
@@ -3304,26 +3332,62 @@ static int switchdevice (struct uae_input_device *id, int num, bool buttonmode)
        return 0;
 }
 
-int input_getqualifiers (void)
+uae_u64 input_getqualifiers (void)
 {
        return qualifiers;
 }
 
-static bool checkqualifiers (int evt, int flags, int qualmask)
+static bool checkqualifiers (int evt, uae_u64 flags, uae_u64 *qualmask, uae_s16 events[MAX_INPUT_SUB_EVENT_ALL])
 {
+       int i, j;
+       int qualid = getqualid (evt);
+       int nomatch = 0;
+
        flags &= ID_FLAG_QUALIFIER_MASK;
+       if (qualid >= 0 && events)
+               qualifiers_evt[qualid] = events;
        /* special set and new qualifier pressed? do not sent it to Amiga-side */
-       if ((qualifiers & ID_FLAG_QUALIFIER_SPECIAL) && isqual (evt))
+       if ((qualifiers & (ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SPECIAL_R)) && qualid >= 0)
                return false;
-       if (!qualmask) // no qualifiers in any slot
-               return true;
-       if (flags == qualifiers || (flags && flags == (qualifiers & ~ID_FLAG_QUALIFIER_SPECIAL)))
-               return true;
-       return false;
+
+       for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
+               if (qualmask[i])
+                       break;
+       }
+       if (i == MAX_INPUT_SUB_EVENT)
+               return true; // no qualifiers in any slot = always match
+
+
+       for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
+               for (j = 0; j < MAX_INPUT_QUALIFIERS; j++) {
+                       uae_u64 mask = (ID_FLAG_QUALIFIER1 | ID_FLAG_QUALIFIER1_R) << (j * 2);
+                       bool isqualmask = (qualmask[i] & mask) != 0;
+                       bool isqual = ((qualifiers &  ~(ID_FLAG_QUALIFIER_SPECIAL | ID_FLAG_QUALIFIER_SPECIAL_R)) & mask) != 0;
+                       if (isqualmask != isqual) {
+                               nomatch++;
+                               break;
+                       }
+               }
+       }
+       if (nomatch == MAX_INPUT_SUB_EVENT) {
+               // no matched qualifiers in any slot
+               // allow all slots without qualifiers
+               return flags ? false : true;
+       }
+
+       for (i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
+               uae_u64 mask = (ID_FLAG_QUALIFIER1 | ID_FLAG_QUALIFIER1_R) << (i * 2);
+               bool isflags = (flags & mask) != 0;
+               bool isqual = (qualifiers & mask) != 0;
+               if (isflags != isqual)
+                       return false;
+       }
+       return true;
 }
+
 static void setqualifiers (int evt, int state)
 {
-       int mask = isqual (evt);
+       uae_u64 mask = isqual (evt);
        if (!mask)
                return;
        if (state)
@@ -3331,12 +3395,14 @@ static void setqualifiers (int evt, int state)
        else
                qualifiers &= ~mask;
 }
-static int getqualmask (struct uae_input_device *id, int num, bool *qualonly)
+
+static uae_u64 getqualmask (uae_u64 *qualmask, struct uae_input_device *id, int num, bool *qualonly)
 {
-       int mask = 0, mask2 = 0;
+       uae_u64 mask = 0, mask2 = 0;
        for (int i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
                int evt = id->eventid[num][i];
                mask |= id->flags[num][i];
+               qualmask[i] = id->flags[num][i] & ID_FLAG_QUALIFIER_MASK;
                mask2 |= isqual (evt);
        }
        mask &= ID_FLAG_QUALIFIER_MASK;
@@ -3349,10 +3415,11 @@ static int getqualmask (struct uae_input_device *id, int num, bool *qualonly)
 }
 
 
-static bool process_custom_event (struct uae_input_device *id, int offset, int state, int qualmask, int autofire, int sub)
+static bool process_custom_event (struct uae_input_device *id, int offset, int state, uae_u64 *qualmask, int autofire, int sub)
 {
-       int idx, slotoffset, flags, custompos, qual;
+       int idx, slotoffset, custompos;
        TCHAR *custom;
+       uae_u64 flags, qual;
 
        if (!id)
                return false;
@@ -3367,7 +3434,7 @@ static bool process_custom_event (struct uae_input_device *id, int offset, int s
                (id->custom[offset][slotoffset] == NULL && id->custom[offset][slotoffset + 2] == NULL) || 
                (id->flags[offset][slotoffset + 2] & ID_FLAG_AUTOFIRE_MASK) || (af & ID_FLAG_AUTOFIRE_MASK)) {
                id->flags[offset][slotoffset] &= ~(ID_FLAG_CUSTOMEVENT_TOGGLED1 | ID_FLAG_CUSTOMEVENT_TOGGLED2);
-               if (checkqualifiers (id->eventid[offset][slotoffset + sub], id->flags[offset][slotoffset + sub], qualmask)) {
+               if (checkqualifiers (id->eventid[offset][slotoffset + sub], id->flags[offset][slotoffset + sub], qualmask, NULL)) {
                        custom = id->custom[offset][slotoffset + sub];
                        if (state && custom) {
                                if (autofire)
@@ -3383,9 +3450,9 @@ static bool process_custom_event (struct uae_input_device *id, int offset, int s
                return false;
 
        slotoffset = 0;
-       if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask)) {
+       if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask, NULL)) {
                slotoffset = 4;
-               if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask))
+               if (!checkqualifiers (id->eventid[offset][slotoffset], id->flags[offset][slotoffset], qualmask, NULL))
                        return false;
        }
 
@@ -3432,7 +3499,7 @@ static void setbuttonstateall (struct uae_input_device *id, struct uae_input_dev
        uae_u32 mask = 1 << button;
        uae_u32 omask = id2 ? id2->buttonmask & mask : 0;
        uae_u32 nmask = (state ? 1 : 0) << button;
-       int qualmask;
+       uae_u64 qualmask[MAX_INPUT_SUB_EVENT];
        bool qualonly;
 
        if (input_play && state)
@@ -3454,14 +3521,14 @@ static void setbuttonstateall (struct uae_input_device *id, struct uae_input_dev
        if (button >= ID_BUTTON_TOTAL)
                return;
 
-       qualmask = getqualmask (id, ID_BUTTON_OFFSET + button, &qualonly);
+       getqualmask (qualmask, id, ID_BUTTON_OFFSET + button, &qualonly);
 
        bool didcustom = false;
 
        for (i = 0; i < MAX_INPUT_SUB_EVENT; i++) {
-               uae_u32 *flagsp = &id->flags[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]];
-               int evt = evt = id->eventid[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]];
-               int flags = flagsp[0];
+               uae_u64 *flagsp = &id->flags[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]];
+               int evt = id->eventid[ID_BUTTON_OFFSET + button][sublevdir[state <= 0 ? 1 : 0][i]];
+               uae_u64 flags = flagsp[0];
                int autofire = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0;
                int toggle = (flags & ID_FLAG_TOGGLE) ? 1 : 0;
                int inverttoggle = (flags & ID_FLAG_INVERTTOGGLE) ? 1 : 0;
@@ -3470,12 +3537,12 @@ static void setbuttonstateall (struct uae_input_device *id, struct uae_input_dev
                        didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, state, qualmask, autofire, i);
                }
 
-               setqualifiers (flags, state > 0);
+               setqualifiers (evt, state > 0);
                if (qualonly)
                        continue;
 
                if (state < 0) {
-                       if (!checkqualifiers (evt, flags, qualmask))
+                       if (!checkqualifiers (evt, flags, qualmask, NULL))
                                continue;
                        handle_input_event (evt, 1, 1, 0, true, false);
                        queue_input_event (evt, NULL, 0, 1, 1, 0); /* send release event next frame */
@@ -3494,14 +3561,14 @@ static void setbuttonstateall (struct uae_input_device *id, struct uae_input_dev
                                continue;
                        if (omask & mask)
                                continue;
-                       if (!checkqualifiers (evt, flags, qualmask))
+                       if (!checkqualifiers (evt, flags, qualmask, NULL))
                                continue;
                        *flagsp ^= ID_FLAG_TOGGLED;
                        int toggled = (*flagsp & ID_FLAG_TOGGLED) ? 1 : 0;
                        handle_input_event (evt, toggled, 1, autofire, true, false);
                        didcustom |= process_custom_event (id, ID_BUTTON_OFFSET + button, toggled, qualmask, autofire, i);
                } else {
-                       if (!checkqualifiers (evt, flags, qualmask)) {
+                       if (!checkqualifiers (evt, flags, qualmask, NULL)) {
                                if (!state && !(flags & ID_FLAG_CANRELEASE)) {
                                        continue;
                                } else if (state) {
@@ -4751,7 +4818,7 @@ static void matchdevices_all (struct uae_prefs *prefs)
        }
 }
 
-bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, int flags, int port)
+bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int num, int evtnum, uae_u64 flags, int port)
 {
        TCHAR name[256];
        struct inputevent *ie;
@@ -4779,7 +4846,8 @@ bool inputdevice_set_gameports_mapping (struct uae_prefs *prefs, int devnum, int
        keyboards = prefs->keyboard_settings[prefs->input_selected_setting];
 
        if (prefs->input_selected_setting != GAMEPORT_INPUT_SETTINGS) {
-               int xflags, xport;
+               int xport;
+               uae_u64 xflags;
                TCHAR xname[MAX_DPATH], xcustom[MAX_DPATH];
                inputdevice_get_mapping (devnum, num, &xflags, &xport, xname, xcustom, 0);
                if (xport == 0)
@@ -5002,6 +5070,39 @@ int inputdevice_synccapslock (int oldcaps, int *capstable)
        return -1;
 }
 
+static void rqualifiers (uae_u64 flags, bool release)
+{
+       uae_u64 mask = ID_FLAG_QUALIFIER1 << 1;
+       for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
+               if ((flags & mask) && (mask & (qualifiers << 1))) {
+                       if (release) {
+                               if (!(mask & qualifiers_r)) {
+                                       qualifiers_r |= mask;
+                                       for (int ii = 0; ii < MAX_INPUT_SUB_EVENT; ii++) {
+                                               int qevt = qualifiers_evt[i][ii];
+                                               if (qevt > 0) {
+                                                       write_log (_T("Released %d '%s'\n"), qevt, events[qevt].name);
+                                                       inputdevice_do_keyboard (events[qevt].data, 0);
+                                               }
+                                       }
+                               }
+                       } else {
+                               if ((mask & qualifiers_r)) {
+                                       qualifiers_r &= ~mask;
+                                       for (int ii = 0; ii < MAX_INPUT_SUB_EVENT; ii++) {
+                                               int qevt = qualifiers_evt[i][ii];
+                                               if (qevt > 0) {
+                                                       write_log (_T("Pressed %d '%s'\n"), qevt, events[qevt].name);
+                                                       inputdevice_do_keyboard (events[qevt].data, 1);
+                                               }
+                                       }
+                               }
+                       }
+               }
+               mask <<= 2;
+       }
+}
+
 static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state, bool qualifiercheckonly)
 {
        struct uae_input_device *na = &keyboards[keyboard];
@@ -5019,13 +5120,15 @@ static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state
        while (j < MAX_INPUT_DEVICE_EVENTS && na->extra[j] >= 0) {
                if (na->extra[j] == scancode) {
                        bool qualonly;
-                       int qualmask = getqualmask (na, j, &qualonly);
+                       uae_u64 qualmask[MAX_INPUT_SUB_EVENT];
+                       getqualmask (qualmask, na, j, &qualonly);
+
                        if (qualonly)
                                qualifiercheckonly = true;
                        for (k = 0; k < MAX_INPUT_SUB_EVENT; k++) {/* send key release events in reverse order */
-                               uae_u32 *flagsp = &na->flags[j][sublevdir[state == 0 ? 1 : 0][k]];
+                               uae_u64 *flagsp = &na->flags[j][sublevdir[state == 0 ? 1 : 0][k]];
                                int evt = na->eventid[j][sublevdir[state == 0 ? 1 : 0][k]];
-                               int flags = *flagsp;
+                               uae_u64 flags = *flagsp;
                                int autofire = (flags & ID_FLAG_AUTOFIRE) ? 1 : 0;
                                int toggle = (flags & ID_FLAG_TOGGLE) ? 1 : 0;
                                int inverttoggle = (flags & ID_FLAG_INVERTTOGGLE) ? 1 : 0;
@@ -5066,7 +5169,7 @@ static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state
                                } else if (toggle) {
                                        if (!state)
                                                continue;
-                                       if (!checkqualifiers (evt, flags, qualmask))
+                                       if (!checkqualifiers (evt, flags, qualmask, na->eventid[j]))
                                                continue;
                                        *flagsp ^= ID_FLAG_TOGGLED;
                                        toggled = (*flagsp & ID_FLAG_TOGGLED) ? 1 : 0;
@@ -5074,12 +5177,14 @@ static int inputdevice_translatekeycode_2 (int keyboard, int scancode, int state
                                        if (k == 0)
                                                didcustom |= process_custom_event (na, j, state, qualmask, autofire, k);
                                } else {
-                                       if (!checkqualifiers (evt, flags, qualmask)) {
+                                       rqualifiers (flags, state ? true : false);
+                                       if (!checkqualifiers (evt, flags, qualmask, na->eventid[j])) {
                                                if (!state && !(flags & ID_FLAG_CANRELEASE))
                                                        continue;
                                                else if (state)
                                                        continue;
                                        }
+
                                        if (state)
                                                *flagsp |= ID_FLAG_CANRELEASE;
                                        else
@@ -5244,7 +5349,7 @@ static struct uae_input_device *get_uid (const struct inputdevice_functions *id,
        return uid;
 }
 
-static int get_event_data (const struct inputdevice_functions *id, int devnum, int num, int *eventid, TCHAR **custom, int *flags, int *port, int sub)
+static int get_event_data (const struct inputdevice_functions *id, int devnum, int num, int *eventid, TCHAR **custom, uae_u64 *flags, int *port, int sub)
 {
        const struct uae_input_device *uid = get_uid (id, devnum);
        int type = id->get_widget_type (devnum, num, 0, 0);
@@ -5295,12 +5400,19 @@ static TCHAR *stripstrdup (const TCHAR *s)
        return out;
 }
 
-static int put_event_data (const struct inputdevice_functions *id, int devnum, int num, int eventid, TCHAR *custom, int flags, int port, int sub)
+static int put_event_data (const struct inputdevice_functions *id, int devnum, int num, int eventid, TCHAR *custom, uae_u64 flags, int port, int sub)
 {
        struct uae_input_device *uid = get_uid (id, devnum);
        int type = id->get_widget_type (devnum, num, 0, 0);
        int i, ret;
 
+       for (i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
+               uae_u64 mask1 = ID_FLAG_QUALIFIER1 << (i * 2);
+               uae_u64 mask2 = mask1 << 1;
+               if ((flags & (mask1 | mask2)) == (mask1 | mask2))
+                       flags &= ~mask2;
+       }
+
        ret = -1;
        if (type == IDEV_WIDGET_BUTTON || type == IDEV_WIDGET_BUTTONAXIS) {
                i = num - id->get_widget_first (devnum, IDEV_WIDGET_BUTTON) + ID_BUTTON_OFFSET;
@@ -5484,7 +5596,8 @@ int inputdevice_iterate (int devnum, int num, TCHAR *name, int *af)
        const struct inputdevice_functions *idf = getidf (devnum);
        static int id_iterator;
        struct inputevent *ie;
-       int mask, data, flags, type;
+       int mask, data, type;
+       uae_u64 flags;
        int devindex = inputdevice_get_device_index (devnum);
 
        *af = 0;
@@ -5536,11 +5649,12 @@ int inputdevice_iterate (int devnum, int num, TCHAR *name, int *af)
 }
 
 // return mapped event from devnum/num/sub
-int inputdevice_get_mapping (int devnum, int num, int *pflags, int *pport, TCHAR *name, TCHAR *custom, int sub)
+int inputdevice_get_mapping (int devnum, int num, uae_u64 *pflags, int *pport, TCHAR *name, TCHAR *custom, int sub)
 {
        const struct inputdevice_functions *idf = getidf (devnum);
        const struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
-       int flags = 0, flag, port, data;
+       int port, data;
+       uae_u64 flags = 0, flag;
        int devindex = inputdevice_get_device_index (devnum);
        TCHAR *customp = NULL;
 
@@ -5585,11 +5699,12 @@ int inputdevice_get_mapping (int devnum, int num, int *pflags, int *pport, TCHAR
 }
 
 // set event name/custom/flags to devnum/num/sub
-int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, int flags, int port, int sub)
+int inputdevice_set_mapping (int devnum, int num, const TCHAR *name, TCHAR *custom, uae_u64 flags, int port, int sub)
 {
        const struct inputdevice_functions *idf = getidf (devnum);
        const struct uae_input_device *uid = get_uid (idf, inputdevice_get_device_index (devnum));
-       int eid, data, flag, portp, amask;
+       int eid, data, portp, amask;
+       uae_u64 flag;
        TCHAR ename[256];
        int devindex = inputdevice_get_device_index (devnum);
        TCHAR *customp = NULL;
index 5db2a20a8adaa2d6035434ce2d7f84feb22cd0b7..16286797dab86a14daa53db948f45256bdbd48c1 100644 (file)
@@ -326,21 +326,21 @@ static int *kbmaps[] = {
        kb_xa1, kb_xa2, kb_arcadia, kb_arcadiaxa, kb_cdtv
 };
 
-static int specialpressed (void)
+static bool specialpressed (void)
 {
-       return input_getqualifiers () & ID_FLAG_QUALIFIER_SPECIAL;
+       return (input_getqualifiers () & ID_FLAG_QUALIFIER_SPECIAL) != 0;
 }
-static int shiftpressed (void)
+static bool shiftpressed (void)
 {
-       return input_getqualifiers () & ID_FLAG_QUALIFIER_SHIFT;
+       return (input_getqualifiers () & ID_FLAG_QUALIFIER_SHIFT) != 0;
 }
-static int altpressed (void)
+static bool altpressed (void)
 {
-       return input_getqualifiers () & ID_FLAG_QUALIFIER_ALT;
+       return (input_getqualifiers () & ID_FLAG_QUALIFIER_ALT) != 0;
 }
-static int ctrlpressed (void)
+static bool ctrlpressed (void)
 {
-       return input_getqualifiers () & ID_FLAG_QUALIFIER_CONTROL;
+       return (input_getqualifiers () & ID_FLAG_QUALIFIER_CONTROL) != 0;
 }
 
 static int capslockstate;
index 4314520ec0db857ab9fc021bed3e2d6414646c15..54d07991e89d03cd38c25a1d4a7c429cffc8989b 100644 (file)
 #define IDC_MBRAM2                      1051
 #define IDC_Z3CHIPMEM                   1052
 #define IDC_Z3CHIPRAM                   1053
-#define IDC_Z3CHIPRAM2                  1054
 #define IDC_MAX32RAM                    1054
 #define IDC_UAEHOME                     1070
 #define IDC_PICASSOHOME                 1071
 #define IDC_CONTRIBUTORS                1124
 #define IDC_BLACKER_THAN_BLACK          1170
 #define IDC_BLITIMM                     1174
+#define IDC_BLITIMM2                    1175
+#define IDC_BLITWAIT                    1175
 #define IDC_LORES                       1176
 #define IDC_RATE2BOX                    1177
 #define IDC_LORES_SMOOTHED              1179
index 69657767f83eaedb633eea2e4b8bf0136ff2b53c..47e0246e65569b9fa1493cd6f3bc63378fbf2f66 100644 (file)
@@ -605,9 +605,9 @@ BEGIN
                     "Button",BS_AUTOCHECKBOX | WS_TABSTOP,100,58,50,10\r
     GROUPBOX        "Options",IDC_STATIC,168,11,114,111\r
     CONTROL         "Immediate Blitter [] Faster but less compatible blitter emulation.",IDC_BLITIMM,\r
-                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,33,96,10\r
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,27,96,10\r
     CONTROL         "Cycle-exact [] The most compatible A500 emulation mode. Very fast PC recommended.",IDC_CYCLEEXACT,\r
-                    "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,179,46,100,10\r
+                    "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,179,53,100,10\r
     GROUPBOX        "Collision Level",IDC_STATIC,14,128,267,48\r
     CONTROL         "None [] Collision hardware emulation disabled.",IDC_COLLISION0,\r
                     "Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,37,144,59,10\r
@@ -618,11 +618,13 @@ BEGIN
     CONTROL         "Full [] 100% collision hardware emulation. Only very few games need this option. Slowest.",IDC_COLLISION3,\r
                     "Button",BS_AUTORADIOBUTTON | WS_TABSTOP,100,160,119,10\r
     CONTROL         "Genlock connected [] Allow boot sequence to detect genlock. Genlock is not emulated.",IDC_GENLOCK,\r
-                    "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,179,59,100,10\r
+                    "Button",BS_AUTOCHECKBOX | BS_LEFT | WS_GROUP | WS_TABSTOP,179,66,100,10\r
     COMBOBOX        IDC_CS_EXT,100,80,49,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\r
     RTEXT           "Chipset Extra",IDC_STATIC,25,79,52,15,SS_CENTERIMAGE\r
-    COMBOBOX        IDC_MONITOREMU,178,99,98,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\r
-    RTEXT           "External display hardware:",IDC_STATIC,174,78,100,15,SS_CENTERIMAGE\r
+    COMBOBOX        IDC_MONITOREMU,178,102,98,65,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP\r
+    RTEXT           "External display hardware:",IDC_STATIC,174,82,100,15,SS_CENTERIMAGE\r
+    CONTROL         "Wait for Blitter [] Pauses the CPU if blitter is active and CPU attempted to modify blitter registers.",IDC_BLITWAIT,\r
+                    "Button",BS_AUTOCHECKBOX | WS_TABSTOP,179,40,96,10\r
 END\r
 \r
 IDD_CHIPSET2 DIALOGEX 0, 65490, 300, 247\r
index 5931cd0c56bdd5ffc69104e150922287d24c116e..20b4e53129c6999d456ef303984bd1eabc7fd3a3 100644 (file)
@@ -239,7 +239,8 @@ bool port_get_custom (int inputmap_port, TCHAR *out)
        for (int i = 0; eventorder[i]; i++) {
                int evtnum = events[i];
                for (int j = 0; j < inputdevicefunc_keyboard.get_widget_num (kbnum); j++) {
-                       int flags, port;
+                       int port;
+                       uae_u64 flags;
                        if (inputdevice_get_mapping (kb + kbnum, j, &flags, &port, NULL, NULL, 0) == evtnum) {
                                if (port == inputmap_port + 1) {
                                        uae_u32 kc = 0;
index d5a2737db15b64b6326eac4d01420a5055a49871..579fcefba3da54c0885fe1b1fd74c59e6a5f9c4a 100644 (file)
@@ -19,8 +19,8 @@
 #define LANG_DLL 1
 
 //#define WINUAEBETA _T("")
-#define WINUAEBETA _T("9")
-#define WINUAEDATE MAKEBD(2012, 8, 1)
+#define WINUAEBETA _T("10")
+#define WINUAEDATE MAKEBD(2012, 8, 6)
 #define WINUAEEXTRA _T("")
 //#define WINUAEEXTRA _T("AmiKit Preview")
 #define WINUAEREV _T("")
index a577428375e8e63795aa5af4b8cb79678e930342..46acb13ea00d9d441c3e5569ef09405ba04272af 100644 (file)
@@ -229,7 +229,7 @@ void getfilterrect2 (RECT *sr, RECT *dr, RECT *zr, int dst_width, int dst_height
                }
        }
 
-       set_custom_limits (-1, -1, -1, -1);
+       bool scl = false;
 
        if (scalemode) {
                int cw, ch, cx, cy, cv;
@@ -258,6 +258,7 @@ void getfilterrect2 (RECT *sr, RECT *dr, RECT *zr, int dst_width, int dst_height
                                        ch -= 25 << currprefs.gfx_vresolution;
                                }
                                set_custom_limits (cw, ch, cx, cy);
+                               scl = true;
                        }
 
                        if (scalemode == AUTOSCALE_INTEGER || scalemode == AUTOSCALE_INTEGER_AUTOSCALE) {
@@ -321,19 +322,29 @@ void getfilterrect2 (RECT *sr, RECT *dr, RECT *zr, int dst_width, int dst_height
 
                        getmanualpos (&cx, &cy, &cw, &ch);
                        set_custom_limits (cw, ch, cx, cy);
+                       scl = true;
 
                        //write_log (_T("%dx%d %dx%d %dx%d\n"), currprefs.gfx_xcenter_pos, currprefs.gfx_ycenter_pos, cx, cy, cw, ch);
 
                        cv = 1;
 
+               } else if (scalemode == AUTOSCALE_CENTER || scalemode == AUTOSCALE_RESIZE) {
+
+                       cv = get_custom_limits (&cw, &ch, &cx, &cy);
+
                } else {
 
                        cv = get_custom_limits (&cw, &ch, &cx, &cy);
-                       if (cv)
+                       if (cv) {
                                set_custom_limits (cw, ch, cx, cy);
+                               scl = true;
+                       }
 
                }
 
+               if (!scl)
+                       set_custom_limits (-1, -1, -1, -1);
+
                if (currprefs.gfx_api == 0) {
                        if (cx < 0)
                                cx = 0;
index c7895b095f83e5b819217495cd054b6f57619e76..ac4d77bd4e68dfd6e701b4194f71403f2b92e4db 100644 (file)
@@ -3327,32 +3327,43 @@ static int input_selected_device, input_selected_widget, input_total_devices;
 static int input_selected_event, input_selected_sub_num;
 static int input_copy_from;
 
-static void getqualifiername (TCHAR *p, int mask)
+static void getqualifiername (TCHAR *p, uae_u64 mask)
 {
-       int i, j;
        *p = 0;
        if (mask == IDEV_MAPPED_QUALIFIER_SPECIAL) {
                _tcscpy (p, _T("*"));
+       } else if (mask == (IDEV_MAPPED_QUALIFIER_SPECIAL << 1)) {
+               _tcscpy (p, _T("* [R]"));
        } else if (mask == IDEV_MAPPED_QUALIFIER_SHIFT) {
                _tcscpy (p, _T("Shift"));
+       } else if (mask == (IDEV_MAPPED_QUALIFIER_SHIFT << 1)) {
+               _tcscpy (p, _T("Shift [R]"));
        } else if (mask == IDEV_MAPPED_QUALIFIER_CONTROL) {
                _tcscpy (p, _T("Ctrl"));
+       } else if (mask == (IDEV_MAPPED_QUALIFIER_CONTROL << 1)) {
+               _tcscpy (p, _T("Ctrl [R]"));
        } else if (mask == IDEV_MAPPED_QUALIFIER_ALT) {
                _tcscpy (p, _T("Alt"));
+       } else if (mask == (IDEV_MAPPED_QUALIFIER_ALT << 1)) {
+               _tcscpy (p, _T("Alt [R]"));
        } else {
-               for (i = IDEV_MAPPED_QUALIFIER1, j = 0; i <= IDEV_MAPPED_QUALIFIER8; i <<= 1, j++) {
-                       if (i == mask)
-                               _stprintf (p, _T("%d"), j + 1);
+               int j;
+               uae_u64 i;
+               for (i = IDEV_MAPPED_QUALIFIER1, j = 0; i <= (IDEV_MAPPED_QUALIFIER8 << 1); i <<= 1, j++) {
+                       if (i == mask) {
+                               _stprintf (p, _T("%d%s"), j / 2 + 1, (j & 1) ? _T(" [R]") : _T(""));
+                       }
                }
        }
 }
 
 static void set_lventry_input (HWND list, int index)
 {
-       int flags, i, sub, port;
+       int i, sub, port;
        TCHAR name[256];
        TCHAR custom[MAX_DPATH];
        TCHAR af[32], toggle[32];
+       uae_u64 flags;
 
        inputdevice_get_mapping (input_selected_device, index, &flags, &port, name, custom, input_selected_sub_num);
        if (flags & IDEV_MAPPED_AUTOFIRE_SET) {
@@ -3383,8 +3394,8 @@ static void set_lventry_input (HWND list, int index)
        if (flags & IDEV_MAPPED_QUALIFIER_MASK) {
                TCHAR *p;
                p = name;
-               for (i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
-                       int mask = IDEV_MAPPED_QUALIFIER1 << i;
+               for (i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) {
+                       uae_u64 mask = IDEV_MAPPED_QUALIFIER1 << i;
                        if (flags & mask) {
                                if (p != name)
                                        *p++ = ',';
@@ -3430,12 +3441,13 @@ static int inputmap_handle (HWND list, int currentdevnum, int currentwidgetnum,
                                struct inputevent *evt = inputdevice_get_eventinfo (evtnum);
                                LV_ITEM lvstruct;
                                int devnum;
-                               int flags, status;
+                               int status;
                                TCHAR name[256];
                                int *atp = axistable;
                                int atpidx;
                                int item;
                                bool found = false;
+                               uae_u64 flags;
 
                                if (list) {
                                        LVGROUP group;
@@ -6264,6 +6276,7 @@ static void values_to_chipsetdlg (HWND hDlg)
        CheckDlgButton (hDlg, IDC_NTSC, workprefs.ntscmode);
        CheckDlgButton (hDlg, IDC_GENLOCK, workprefs.genlock);
        CheckDlgButton (hDlg, IDC_BLITIMM, workprefs.immediate_blits);
+       CheckDlgButton (hDlg, IDC_BLITWAIT, workprefs.waiting_blits);
        CheckRadioButton (hDlg, IDC_COLLISION0, IDC_COLLISION3, IDC_COLLISION0 + workprefs.collision_level);
        CheckDlgButton (hDlg, IDC_CYCLEEXACT, workprefs.cpu_cycle_exact);
        SendDlgItemMessage (hDlg, IDC_CS_EXT, CB_SETCURSEL, workprefs.cs_compatible, 0);
@@ -6279,6 +6292,7 @@ static void values_from_chipsetdlg (HWND hDlg, UINT msg, WPARAM wParam, LPARAM l
 
        workprefs.genlock = ischecked (hDlg, IDC_GENLOCK);
        workprefs.immediate_blits = ischecked (hDlg, IDC_BLITIMM);
+       workprefs.waiting_blits = ischecked (hDlg, IDC_BLITWAIT) ? 1 : 0;
        n = ischecked (hDlg, IDC_CYCLEEXACT);
        if (workprefs.cpu_cycle_exact != n) {
                workprefs.cpu_cycle_exact = workprefs.blitter_cycle_exact = n;
@@ -11761,7 +11775,8 @@ static void clearinputlistview (HWND hDlg)
 static void doinputcustom (HWND hDlg, int newcustom)
 {
        TCHAR custom1[MAX_DPATH];
-       int flags;
+       uae_u64 flags;
+
        custom1[0] = 0;
        inputdevice_get_mapping (input_selected_device, input_selected_widget,
                &flags, NULL, NULL, custom1, input_selected_sub_num);
@@ -11843,7 +11858,7 @@ static void values_from_inputdlg (HWND hDlg, int inputchange)
        }
 
        if (inputchange && doselect && input_selected_device >= 0 && input_selected_event >= 0) {
-               int flags;
+               uae_u64 flags;
                bool iscustom = false;
                TCHAR custom[MAX_DPATH];
 
@@ -12320,9 +12335,11 @@ static void handlerawinput (HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
 
 static void input_toggleautofire (void)
 {
-       int flags, evt;
+       int evt;
+       uae_u64 flags;
        TCHAR name[256];
        TCHAR custom[MAX_DPATH];
+
        if (input_selected_device < 0 || input_selected_widget < 0)
                return;
        evt = inputdevice_get_mapping (input_selected_device, input_selected_widget,
@@ -12370,11 +12387,12 @@ static int genericpopupmenu (HWND hwnd, TCHAR **items, int *flags, int num)
 
 static void input_qualifiers (HWND hDlg)
 {
-       int flags, evt, item;
+       uae_u64 flags;
+       int evt, item;
        TCHAR name[256];
        TCHAR custom[MAX_DPATH];
-       TCHAR *names[MAX_INPUT_QUALIFIERS];
-       int mflags[MAX_INPUT_QUALIFIERS];
+       TCHAR *names[MAX_INPUT_QUALIFIERS * 2];
+       int mflags[MAX_INPUT_QUALIFIERS * 2];
        TCHAR tmp[MAX_DPATH];
        
        if (input_selected_device < 0 || input_selected_widget < 0)
@@ -12384,29 +12402,31 @@ static void input_qualifiers (HWND hDlg)
        if (evt <= 0)
                name[0] = 0;
        
-       for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
+       for (int i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) {
                getqualifiername (tmp, IDEV_MAPPED_QUALIFIER1 << i);
                mflags[i] = 0;
                if (flags & (IDEV_MAPPED_QUALIFIER1 << i))
                        mflags[i] = 1;
                names[i] = my_strdup (tmp);
        }
-       item = genericpopupmenu (hDlg, names, mflags, MAX_INPUT_QUALIFIERS);
+       item = genericpopupmenu (hDlg, names, mflags, MAX_INPUT_QUALIFIERS * 2);
        if (item >= 0)
                flags ^= IDEV_MAPPED_QUALIFIER1 << item;
 
        inputdevice_set_mapping (input_selected_device, input_selected_widget,
                name, custom, flags, -1, input_selected_sub_num);
 
-       for (int i = 0; i < MAX_INPUT_QUALIFIERS; i++) {
+       for (int i = 0; i < MAX_INPUT_QUALIFIERS * 2; i++) {
                xfree (names[i]);
        }
 }
 static void input_toggletoggle (void)
 {
-       int flags, evt;
+       int evt;
+       uae_u64 flags;
        TCHAR name[256];
        TCHAR custom[MAX_DPATH];
+
        if (input_selected_device < 0 || input_selected_widget < 0)
                return;
        evt = inputdevice_get_mapping (input_selected_device, input_selected_widget,
index 3d47a0f50b364e278e52c3c90f7b62bd591e6c7b..2e11a2986156b7629b72e31de023a1d63cc20b13 100644 (file)
@@ -1,6 +1,27 @@
 
 - restore only single input target to default.
 
+Beta 10:
+
+- BPLxDAT CPU/Copper writes are now accurately emulated. (Blerkenwiegel/Scoopex)
+- COPJMPx triggered second cycle is special, does not need to be free but if it is free, it is allocated for copper.
+  (EyeQlazer/Scoopex is now 100% correct)
+- Emulate copper waiting + CPU write to COPJMPx slightly different copper cycle usage.
+- Fixed chipset emulation infinite loop if program crashed and wrote totally bogus values to programmable display
+  refresh rate registers.
+- Both mouse and joystick enabled in same port: moving joystick does not cause mouse big cursor jumps anymore.
+- Automatic center option incorrectly set display limits to autoscale limits (black borders).
+- "Release" key qualifier support. When [R] qualifier is selected, qualifier key is released before sending mapped
+  keycode and then immediately pressed again. Qualifier selection GUI is currently ugly.
+- Modified Input Qualifier support, now non-matched qualifier combinations (one or more qualifiers pressed but no
+  match in any 8 slots) always trigger non-qualifier input target(s), previously nothing was triggered.
+- Added "Wait for Blitter" GUI option, when enabled, CPU is paused if blitter is active and CPU attempted to modify
+  blitter registers. Previously was always enabled if fastest possible CPU (and still is), now it can be manually
+  enabled in other modes, can be useful when running 68020/AGA programs that run badly in non-ce modes but also have
+  some display problems in ce modes. (because of not accurate enough CPU speed)
+- Fixed flickering graphics corruption in some programs (for example Disposable Hero), also could have caused
+  reduced performance. (b1 display limit feature)
+
 Beta 9:
 
 - Replaced readpu.c 68020+ special case TST An/PC-rel and CMP #imm,PC-rel variants with proper table68k entries.