1 
2 /*
3 * UAE - The Un*x Amiga Emulator
4 *
5 * Screen drawing functions
6 *
7 * Copyright 1995-2000 Bernd Schmidt
8 * Copyright 1995 Alessandro Bissacco
9 * Copyright 2000-2008 Toni Wilen
10 */
11 
12 /* There are a couple of concepts of "coordinates" in this file.
13 - DIW coordinates
14 - DDF coordinates (essentially cycles, resolution lower than lores by a factor of 2)
15 - Pixel coordinates
16 * in the Amiga's resolution as determined by BPLCON0 ("Amiga coordinates")
17 * in the window resolution as determined by the preferences ("window coordinates").
18 * in the window resolution, and with the origin being the topmost left corner of
19 the window ("native coordinates")
20 One note about window coordinates.  The visible area depends on the width of the
21 window, and the centering code.  The first visible horizontal window coordinate is
22 often _not_ 0, but the value of VISIBLE_LEFT_BORDER instead.
23 
24 One important thing to remember: DIW coordinates are in the lowest possible
25 resolution.
26 
27 To prevent extremely bad things (think pixels cut in half by window borders) from
28 happening, all ports should restrict window widths to be multiples of 16 pixels.  */
29 
30 #include "sysconfig.h"
31 #include "sysdeps.h"
32 
33 #include <ctype.h>
34 #include <assert.h>
35 
36 #include "options.h"
37 #include "threaddep/thread.h"
38 #include "uae.h"
39 #include "uae/memory.h"
40 #include "custom.h"
41 #include "newcpu.h"
42 #include "xwin.h"
43 #include "autoconf.h"
44 #include "gui.h"
45 #include "picasso96.h"
46 #include "drawing.h"
47 #include "savestate.h"
48 #include "statusline.h"
49 #include "inputdevice.h"
50 #include "debug.h"
51 #include "cd32_fmv.h"
52 #include "specialmonitors.h"
53 
54 #define BG_COLOR_DEBUG 0
55 //#define XLINECHECK
56 
57 extern int sprite_buffer_res;
58 static int lores_factor;
59 int lores_shift;
60 
61 static void pfield_set_linetoscr(void);
62 
63 int debug_bpl_mask = 0xff, debug_bpl_mask_one;
64 
lores_set(int lores)65 static void lores_set(int lores)
66 {
67 	int old = lores;
68 	lores_shift = lores;
69 	if (lores_shift != old)
70 		pfield_set_linetoscr();
71 }
72 
lores_reset(void)73 static void lores_reset (void)
74 {
75 	lores_factor = currprefs.gfx_resolution ? 2 : 1;
76 	lores_set(currprefs.gfx_resolution);
77 	if (doublescan > 0) {
78 		if (lores_shift < 2)
79 			lores_shift++;
80 		lores_factor = 2;
81 		lores_set(lores_shift);
82 	}
83 	sprite_buffer_res = currprefs.gfx_resolution;
84 	if (doublescan > 0 && sprite_buffer_res < RES_SUPERHIRES)
85 		sprite_buffer_res++;
86 }
87 
88 bool aga_mode; /* mirror of chipset_mask & CSMASK_AGA */
89 bool direct_rgb;
90 
91 /* The shift factor to apply when converting between Amiga coordinates and window
92 coordinates.  Zero if the resolution is the same, positive if window coordinates
93 have a higher resolution (i.e. we're stretching the image), negative if window
94 coordinates have a lower resolution (i.e. we're shrinking the image).  */
95 static int res_shift;
96 
97 static int linedbl, linedbld;
98 
99 int interlace_seen = 0;
100 #define AUTO_LORES_FRAMES 10
101 static int can_use_lores = 0, frame_res, frame_res_lace;
102 static int resolution_count[RES_MAX + 1], lines_count;
103 static bool center_reset;
104 static bool need_genlock_data, init_genlock_data;
105 
106 /* Lookup tables for dual playfields.  The dblpf_*1 versions are for the case
107 that playfield 1 has the priority, dbplpf_*2 are used if playfield 2 has
108 priority.  If we need an array for non-dual playfield mode, it has no number.  */
109 /* The dbplpf_ms? arrays contain a shift value.  plf_spritemask is initialized
110 to contain two 16 bit words, with the appropriate mask if pf1 is in the
111 foreground being at bit offset 0, the one used if pf2 is in front being at
112 offset 16.  */
113 
114 static int dblpf_ms1[256], dblpf_ms2[256], dblpf_ms[256];
115 static int dblpf_ind1[256], dblpf_ind2[256];
116 
117 static int dblpf_2nd1[256], dblpf_2nd2[256];
118 
119 static const int dblpfofs[] = { 0, 2, 4, 8, 16, 32, 64, 128 };
120 
121 static int sprite_offs[256];
122 
123 static uae_u32 clxtab[256];
124 
125 /* Video buffer description structure. Filled in by the graphics system
126 * dependent code. */
127 
128 struct vidbuf_description gfxvidinfo;
129 
130 /* OCS/ECS color lookup table. */
131 xcolnr xcolors[4096];
132 
133 struct spritepixelsbuf {
134 	uae_u8 attach;
135 	uae_u8 stdata;
136 	uae_u16 data;
137 };
138 static struct spritepixelsbuf spritepixels_buffer[MAX_PIXELS_PER_LINE];
139 static struct spritepixelsbuf *spritepixels;
140 static int sprite_first_x, sprite_last_x;
141 
142 /* AGA mode color lookup tables */
143 unsigned int xredcolors[256], xgreencolors[256], xbluecolors[256];
144 #ifdef AGA
145 static int dblpf_ind1_aga[256], dblpf_ind2_aga[256];
146 #else
147 static uae_u8 spriteagadpfpixels[1];
148 static int dblpf_ind1_aga[1], dblpf_ind2_aga[1];
149 #endif
150 int xredcolor_s, xredcolor_b, xredcolor_m;
151 int xgreencolor_s, xgreencolor_b, xgreencolor_m;
152 int xbluecolor_s, xbluecolor_b, xbluecolor_m;
153 
154 struct color_entry colors_for_drawing;
155 
156 /* The size of these arrays is pretty arbitrary; it was chosen to be "more
157 than enough".  The coordinates used for indexing into these arrays are
158 almost, but not quite, Amiga coordinates (there's a constant offset).  */
159 static union {
160 	/* Let's try to align this thing. */
161 	double uupzuq;
162 	long int cruxmedo;
163 	uae_u8 apixels[MAX_PIXELS_PER_LINE * 2];
164 	uae_u16 apixels_w[MAX_PIXELS_PER_LINE * 2 / sizeof (uae_u16)];
165 	uae_u32 apixels_l[MAX_PIXELS_PER_LINE * 2 / sizeof (uae_u32)];
166 } pixdata;
167 
168 static uae_u8 *refresh_indicator_buffer;
169 static uae_u8 *refresh_indicator_changed, *refresh_indicator_changed_prev;
170 static int refresh_indicator_height;
171 
172 #ifdef OS_WITHOUT_MEMORY_MANAGEMENT
173 uae_u16 *spixels;
174 #else
175 uae_u16 spixels[2 * MAX_SPR_PIXELS];
176 #endif
177 
178 /* Eight bits for every pixel.  */
179 union sps_union spixstate;
180 
181 static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2];
182 static uae_u8 *real_bplpt[8];
183 
184 static uae_u8 all_ones[MAX_PIXELS_PER_LINE];
185 static uae_u8 all_zeros[MAX_PIXELS_PER_LINE];
186 
187 uae_u8 *xlinebuffer, *xlinebuffer_genlock;
188 
189 static int *amiga2aspect_line_map, *native2amiga_line_map;
190 static uae_u8 **row_map;
191 static uae_u8 *row_map_genlock_buffer;
192 static uae_u8 row_tmp[MAX_PIXELS_PER_LINE * 32 / 8];
193 static int max_drawn_amiga_line;
194 uae_u8 **row_map_genlock;
195 
196 /* line_draw_funcs: pfield_do_linetoscr, pfield_do_fill_line, decode_ham */
197 typedef void (*line_draw_func)(int, int, bool);
198 
199 #define LINE_UNDECIDED 1
200 #define LINE_DECIDED 2
201 #define LINE_DECIDED_DOUBLE 3
202 #define LINE_AS_PREVIOUS 4
203 #define LINE_BLACK 5
204 #define LINE_REMEMBERED_AS_BLACK 6
205 #define LINE_DONE 7
206 #define LINE_DONE_AS_PREVIOUS 8
207 #define LINE_REMEMBERED_AS_PREVIOUS 9
208 
209 #define LINESTATE_SIZE ((MAXVPOS + 2) * 2 + 1)
210 
211 static uae_u8 linestate[LINESTATE_SIZE];
212 
213 uae_u8 line_data[(MAXVPOS + 2) * 2][MAX_PLANES * MAX_WORDS_PER_LINE * 2];
214 
215 /* Centering variables.  */
216 static int min_diwstart, max_diwstop;
217 /* The visible window: VISIBLE_LEFT_BORDER contains the left border of the visible
218 area, VISIBLE_RIGHT_BORDER the right border.  These are in window coordinates.  */
219 int visible_left_border, visible_right_border;
220 /* Pixels outside of visible_start and visible_stop are always black */
221 static int visible_left_start, visible_right_stop;
222 static int visible_top_start, visible_bottom_stop;
223 /* same for hblank */
224 static int hblank_left_start, hblank_right_stop;
225 
226 static int linetoscr_x_adjust_pixbytes, linetoscr_x_adjust_pixels;
227 static int thisframe_y_adjust;
228 static int thisframe_y_adjust_real, max_ypos_thisframe, min_ypos_for_screen;
229 int thisframe_first_drawn_line, thisframe_last_drawn_line;
230 
231 /* A frame counter that forces a redraw after at least one skipped frame in
232 interlace mode.  */
233 static int last_redraw_point;
234 
235 #define MAX_STOP 30000
236 static int first_drawn_line, last_drawn_line;
237 static int first_block_line, last_block_line;
238 
239 #define NO_BLOCK -3
240 
241 /* These are generated by the drawing code from the line_decisions array for
242 each line that needs to be drawn.  These are basically extracted out of
243 bit fields in the hardware registers.  */
244 static int bplehb, bplham, bpldualpf, bpldualpfpri, bpldualpf2of, bplplanecnt, ecsshres;
245 static bool issprites;
246 static int bplres;
247 static int plf1pri, plf2pri, bplxor, bpldelay_sh;
248 static uae_u32 plf_sprite_mask;
249 static int sbasecol[2] = { 16, 16 };
250 static int hposblank;
251 static bool specialmonitoron;
252 static bool ecs_genlock_features_active;
253 static uae_u8 ecs_genlock_features_mask;
254 static bool ecs_genlock_features_colorkey;
255 
256 bool picasso_requested_on;
257 bool picasso_on;
258 
259 uae_sem_t gui_sem;
260 int inhibit_frame;
261 
262 int framecnt;
263 int custom_frame_redraw_necessary;
264 static int frame_redraw_necessary;
265 static int picasso_redraw_necessary;
266 
267 #ifdef XLINECHECK
xlinecheck(unsigned int start,unsigned int end)268 static void xlinecheck (unsigned int start, unsigned int end)
269 {
270 	unsigned int xstart = (unsigned int)xlinebuffer + start * gfxvidinfo.drawbuffer.pixbytes;
271 	unsigned int xend = (unsigned int)xlinebuffer + end * gfxvidinfo.drawbuffer.pixbytes;
272 	unsigned int end1 = (unsigned int)gfxvidinfo.drawbuffer.bufmem + gfxvidinfo.drawbuffer.rowbytes * gfxvidinfo.drawbuffer.height;
273 	int min = linetoscr_x_adjust_bytes / gfxvidinfo.drawbuffer.pixbytes;
274 	int ok = 1;
275 
276 	if (xstart >= gfxvidinfo.drawbuffer.emergmem && xstart < gfxvidinfo.drawbuffer.emergmem + 4096 * gfxvidinfo.drawbuffer.pixbytes &&
277 		xend >= gfxvidinfo.drawbuffer.emergmem && xend < gfxvidinfo.drawbuffer.emergmem + 4096 * gfxvidinfo.drawbuffer.pixbytes)
278 		return;
279 
280 	if (xstart < (unsigned int)gfxvidinfo.drawbuffer.bufmem || xend < (unsigned int)gfxvidinfo.drawbuffer.bufmem)
281 		ok = 0;
282 	if (xend > end1 || xstart >= end1)
283 		ok = 0;
284 	xstart -= (unsigned int)gfxvidinfo.drawbuffer.bufmem;
285 	xend -= (unsigned int)gfxvidinfo.drawbuffer.bufmem;
286 	if ((xstart % gfxvidinfo.drawbuffer.rowbytes) >= gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes)
287 		ok = 0;
288 	if ((xend % gfxvidinfo.drawbuffer.rowbytes) >= gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes)
289 		ok = 0;
290 	if (xstart >= xend)
291 		ok = 0;
292 	if (xend - xstart > gfxvidinfo.drawbuffer.width * gfxvidinfo.drawbuffer.pixbytes)
293 		ok = 0;
294 
295 	if (!ok) {
296 		write_log (_T("*** %d-%d (%dx%dx%d %d) %p\n"),
297 			start - min, end - min, gfxvidinfo.drawbuffer.width, gfxvidinfo.drawbuffer.height,
298 			gfxvidinfo.drawbuffer.pixbytes, gfxvidinfo.drawbuffer.rowbytes,
299 			xlinebuffer);
300 	}
301 }
302 #else
303 #define xlinecheck(start, end)
304 #endif
305 
clearbuffer(struct vidbuffer * dst)306 static void clearbuffer (struct vidbuffer *dst)
307 {
308 	if (!dst->bufmem_allocated)
309 		return;
310 	uae_u8 *p = dst->bufmem_allocated;
311 	for (int y = 0; y < dst->height_allocated; y++) {
312 		memset (p, 0, dst->width_allocated * dst->pixbytes);
313 		p += dst->rowbytes;
314 	}
315 }
316 
reset_decision_table(void)317 static void reset_decision_table (void)
318 {
319 	for (int i = 0; i < sizeof linestate / sizeof *linestate; i++) {
320 		linestate[i] = LINE_UNDECIDED;
321 	}
322 }
323 
count_frame(void)324 STATIC_INLINE void count_frame (void)
325 {
326 	framecnt++;
327 	if (framecnt >= currprefs.gfx_framerate)
328 		framecnt = 0;
329 	if (inhibit_frame)
330 		framecnt = 1;
331 }
332 
xshift(int x,int shift)333 STATIC_INLINE int xshift (int x, int shift)
334 {
335 	if (shift < 0)
336 		return x >> (-shift);
337 	else
338 		return x << shift;
339 }
340 
coord_native_to_amiga_x(int x)341 int coord_native_to_amiga_x (int x)
342 {
343 	x += visible_left_border;
344 	x = xshift (x, 1 - lores_shift);
345 	return x + 2 * DISPLAY_LEFT_SHIFT - 2 * DIW_DDF_OFFSET;
346 }
347 
coord_native_to_amiga_y(int y)348 int coord_native_to_amiga_y (int y)
349 {
350 	return native2amiga_line_map[y] + thisframe_y_adjust - minfirstline;
351 }
352 
res_shift_from_window(int x)353 STATIC_INLINE int res_shift_from_window (int x)
354 {
355 	if (res_shift >= 0)
356 		return x >> res_shift;
357 	return x << -res_shift;
358 }
359 
res_shift_from_amiga(int x)360 STATIC_INLINE int res_shift_from_amiga (int x)
361 {
362 	if (res_shift >= 0)
363 		return x >> res_shift;
364 	return x << -res_shift;
365 }
366 
notice_screen_contents_lost(void)367 void notice_screen_contents_lost (void)
368 {
369 	picasso_redraw_necessary = 1;
370 	frame_redraw_necessary = 2;
371 }
372 
isnativevidbuf(void)373 bool isnativevidbuf (void)
374 {
375 	if (gfxvidinfo.outbuffer == NULL)
376 		return false;
377 	if (gfxvidinfo.outbuffer == &gfxvidinfo.drawbuffer)
378 		return true;
379 	return gfxvidinfo.outbuffer->nativepositioning;
380 }
381 
382 extern int plffirstline_total, plflastline_total;
383 extern int first_planes_vpos, last_planes_vpos;
384 extern int diwfirstword_total, diwlastword_total;
385 extern int ddffirstword_total, ddflastword_total;
386 extern bool vertical_changed, horizontal_changed;
387 extern int firstword_bplcon1;
388 extern int lof_store;
389 
390 #define MIN_DISPLAY_W 256
391 #define MIN_DISPLAY_H 192
392 #define MAX_DISPLAY_W 362
393 #define MAX_DISPLAY_H 283
394 
395 static int gclow, gcloh, gclox, gcloy, gclorealh;
396 static int stored_left_start, stored_top_start, stored_width, stored_height;
397 
get_custom_topedge(int * xp,int * yp,bool max)398 void get_custom_topedge (int *xp, int *yp, bool max)
399 {
400 
401 	if (isnativevidbuf () && !max) {
402 		int x, y;
403 		x = visible_left_border + (DISPLAY_LEFT_SHIFT << currprefs.gfx_resolution);
404 		y = minfirstline << currprefs.gfx_vresolution;
405 #if 0
406 		int dbl1, dbl2;
407 		dbl2 = dbl1 = currprefs.gfx_vresolution;
408 		if (doublescan > 0 && interlace_seen <= 0) {
409 			dbl1--;
410 			dbl2--;
411 		}
412 		x = -(visible_left_border + (DISPLAY_LEFT_SHIFT << currprefs.gfx_resolution));
413 		y = -minfirstline << currprefs.gfx_vresolution;
414 		y = xshift (y, dbl2);
415 #endif
416 		*xp = x;
417 		*yp = y;
418 	} else {
419 		*xp = 0;
420 		*yp = 0;
421 	}
422 }
423 
reset_custom_limits(void)424 static void reset_custom_limits (void)
425 {
426 	gclow = gcloh = gclox = gcloy = 0;
427 	gclorealh = -1;
428 	center_reset = true;
429 }
430 
set_blanking_limits(void)431 static void set_blanking_limits (void)
432 {
433 	hblank_left_start = visible_left_start;
434 	hblank_right_stop = visible_right_stop;
435 
436 	if (programmedmode) {
437 		if (hblank_left_start < coord_hw_to_window_x (hsyncendpos * 2))
438 			hblank_left_start = coord_hw_to_window_x (hsyncendpos * 2);
439 		if (hblank_right_stop > coord_hw_to_window_x (hsyncstartpos * 2))
440 			hblank_right_stop = coord_hw_to_window_x (hsyncstartpos * 2);
441 	}
442 }
443 
get_custom_raw_limits(int * pw,int * ph,int * pdx,int * pdy)444 void get_custom_raw_limits (int *pw, int *ph, int *pdx, int *pdy)
445 {
446 	if (stored_width > 0) {
447 		*pw = stored_width;
448 		*ph = stored_height;
449 		*pdx = stored_left_start;
450 		*pdy = stored_top_start;
451 	} else {
452 		int x = visible_left_border;
453 		if (x < visible_left_start)
454 			x = visible_left_start;
455 		*pdx = x;
456 		int x2 = visible_right_border;
457 		if (x2 > visible_right_stop)
458 			x2 = visible_right_stop;
459 		*pw = x2 - x;
460 		int y = min_ypos_for_screen;
461 		if (y < visible_top_start)
462 			y = visible_top_start;
463 		*pdy = y;
464 		int y2 = max_ypos_thisframe;
465 		if (y2 > visible_bottom_stop)
466 			y2 = visible_bottom_stop;
467 		*ph = y2 - y;
468 	}
469 }
470 
check_custom_limits(void)471 void check_custom_limits(void)
472 {
473 	int vls = visible_left_start;
474 	int vrs = visible_right_stop;
475 	int vts = visible_top_start;
476 	int vbs = visible_bottom_stop;
477 
478 	struct gfx_filterdata *fd = &currprefs.gf[0];
479 	int left = fd->gfx_filter_left_border >> (RES_MAX - currprefs.gfx_resolution);
480 	int right = fd->gfx_filter_right_border >> (RES_MAX - currprefs.gfx_resolution);
481 	int top = fd->gfx_filter_top_border;
482 	int bottom = fd->gfx_filter_bottom_border;
483 
484 	if (left > visible_left_start)
485 		visible_left_start = left;
486 	if (right > left && right < visible_right_stop)
487 		visible_right_stop = right;
488 
489 	if (top > visible_top_start)
490 		visible_top_start = top;
491 	if (bottom > top && bottom < visible_bottom_stop)
492 		visible_bottom_stop = bottom;
493 
494 	set_blanking_limits ();
495 }
496 
set_custom_limits(int w,int h,int dx,int dy)497 void set_custom_limits (int w, int h, int dx, int dy)
498 {
499 	int vls = visible_left_start;
500 	int vrs = visible_right_stop;
501 	int vts = visible_top_start;
502 	int vbs = visible_bottom_stop;
503 
504 	if (w <= 0 || dx < 0) {
505 		visible_left_start = 0;
506 		visible_right_stop = MAX_STOP;
507 	} else {
508 		visible_left_start = visible_left_border + dx;
509 		visible_right_stop = visible_left_start + w;
510 	}
511 	if (h <= 0 || dy < 0) {
512 		visible_top_start = 0;
513 		visible_bottom_stop = MAX_STOP;
514 	} else {
515 		visible_top_start = min_ypos_for_screen + dy;
516 		visible_bottom_stop = visible_top_start + h;
517 	}
518 
519 	if (vls != visible_left_start || vrs != visible_right_stop ||
520 		vts != visible_top_start || vbs != visible_bottom_stop)
521 		notice_screen_contents_lost ();
522 
523 	check_custom_limits();
524 }
525 
store_custom_limits(int w,int h,int x,int y)526 void store_custom_limits (int w, int h, int x, int y)
527 {
528 	stored_left_start = x;
529 	stored_top_start = y;
530 	stored_width = w;
531 	stored_height = h;
532 #if 0
533 	write_log (_T("%dx%d %dx%d %dx%d %dx%d %d\n"), x, y, w, h,
534 	   	currprefs.gfx_xcenter_pos,
535 		currprefs.gfx_ycenter_pos,
536 		currprefs.gfx_xcenter_size,
537 		currprefs.gfx_ycenter_size,
538 		currprefs.gfx_filter_autoscale);
539 #endif
540 }
541 
get_custom_limits(int * pw,int * ph,int * pdx,int * pdy,int * prealh)542 int get_custom_limits (int *pw, int *ph, int *pdx, int *pdy, int *prealh)
543 {
544 	int w, h, dx, dy, y1, y2, dbl1, dbl2;
545 	int ret = 0;
546 
547 	if (!pw || !ph || !pdx || !pdy) {
548 		reset_custom_limits ();
549 		return 0;
550 	}
551 
552 	if (!isnativevidbuf ()) {
553 		*pw = gfxvidinfo.outbuffer->outwidth;
554 		*ph = gfxvidinfo.outbuffer->outheight;
555 		*pdx = 0;
556 		*pdy = 0;
557 		*prealh = -1;
558 		return 1;
559 	}
560 
561 	*pw = gclow;
562 	*ph = gcloh;
563 	*pdx = gclox;
564 	*pdy = gcloy;
565 	*prealh = gclorealh;
566 
567 	if (gclow > 0 && gcloh > 0)
568 		ret = -1;
569 
570 	if (interlace_seen) {
571 		static int interlace_count;
572 		// interlace = only use long frames
573 		if (lof_store && (interlace_count & 1) == 0)
574 			interlace_count++;
575 		if (!lof_store && (interlace_count & 1) != 0)
576 			interlace_count++;
577 		if (interlace_count < 3)
578 			return ret;
579 		if (!lof_store)
580 			return ret;
581 		interlace_count = 0;
582 		/* program may have set last visible line as last possible line (CD32 boot screen) */
583 		if (last_planes_vpos < maxvpos)
584 			last_planes_vpos++;
585 		if (plflastline_total < maxvpos)
586 			plflastline_total++;
587 	}
588 
589 	if (plflastline_total < 4)
590 		plflastline_total = last_planes_vpos;
591 
592 	ddffirstword_total = coord_hw_to_window_x (ddffirstword_total * 2 + DIW_DDF_OFFSET);
593 	ddflastword_total = coord_hw_to_window_x (ddflastword_total * 2 + DIW_DDF_OFFSET);
594 
595 	if (doublescan <= 0 && !programmedmode) {
596 		int min = coord_diw_to_window_x (92);
597 		int max = coord_diw_to_window_x (460);
598 		if (diwfirstword_total < min)
599 			diwfirstword_total = min;
600 		if (diwlastword_total > max)
601 			diwlastword_total = max;
602 		if (ddffirstword_total < min)
603 			ddffirstword_total = min;
604 		if (ddflastword_total > max)
605 			ddflastword_total = max;
606 		if (0 && !(currprefs.chipset_mask & CSMASK_AGA)) {
607 			if (ddffirstword_total > diwfirstword_total)
608 				diwfirstword_total = ddffirstword_total;
609 			if (ddflastword_total < diwlastword_total)
610 				diwlastword_total = ddflastword_total;
611 		}
612 	}
613 
614 	w = diwlastword_total - diwfirstword_total;
615 	dx = diwfirstword_total - visible_left_border;
616 
617 	y2 = plflastline_total;
618 	if (y2 > last_planes_vpos)
619 		y2 = last_planes_vpos;
620 	y1 = plffirstline_total;
621 	if (first_planes_vpos > y1)
622 		y1 = first_planes_vpos;
623 	if (minfirstline > y1)
624 		y1 = minfirstline;
625 
626 	dbl2 = dbl1 = currprefs.gfx_vresolution;
627 	if (doublescan > 0 && interlace_seen <= 0) {
628 		dbl1--;
629 		dbl2--;
630 	}
631 
632 	h = y2 - y1;
633 	dy = y1 - minfirstline;
634 
635 	if (first_planes_vpos == 0) {
636 		// no planes enabled during frame
637 		if (ret < 0)
638 			return 1;
639 		h = currprefs.ntscmode ? 200 : 240;
640 		w = 320 << currprefs.gfx_resolution;
641 		dy = 36 / 2;
642 #ifdef FSUAE
643 		dx = 74;
644 #else
645 		dx = 58;
646 #endif
647 	}
648 
649 	if (dx < 0)
650 		dx = 0;
651 
652 	*prealh = -1;
653 	if (!programmedmode && first_planes_vpos) {
654 		int th = (maxvpos - minfirstline) * 95 / 100;
655 		if (th > h) {
656 			th = xshift (th, dbl1);
657 			*prealh = th;
658 		}
659 	}
660 
661 	dy = xshift (dy, dbl2);
662 	h = xshift (h, dbl1);
663 
664 	if (w == 0 || h == 0)
665 		return 0;
666 
667 	if (doublescan <= 0 && !programmedmode) {
668 		if ((w >> currprefs.gfx_resolution) < MIN_DISPLAY_W) {
669 			dx += (w - (MIN_DISPLAY_W << currprefs.gfx_resolution)) / 2;
670 			w = MIN_DISPLAY_W << currprefs.gfx_resolution;
671 		}
672 		if ((h >> dbl1) < MIN_DISPLAY_H) {
673 			dy += (h - (MIN_DISPLAY_H << dbl1)) / 2;
674 			h = MIN_DISPLAY_H << dbl1;
675 		}
676 		if ((w >> currprefs.gfx_resolution) > MAX_DISPLAY_W) {
677 			dx += (w - (MAX_DISPLAY_W << currprefs.gfx_resolution)) / 2;
678 			w = MAX_DISPLAY_W << currprefs.gfx_resolution;
679 		}
680 		if ((h >> dbl1) > MAX_DISPLAY_H) {
681 			dy += (h - (MAX_DISPLAY_H << dbl1)) / 2;
682 			h = MAX_DISPLAY_H << dbl1;
683 		}
684 	}
685 
686 	if (gclow == w && gcloh == h && gclox == dx && gcloy == dy)
687 		return ret;
688 
689 	if (w <= 0 || h <= 0 || dx < 0 || dy < 0)
690 		return ret;
691 	if (doublescan <= 0 && !programmedmode) {
692 		if (dx > gfxvidinfo.outbuffer->inwidth / 3)
693 			return ret;
694 		if (dy > gfxvidinfo.outbuffer->inheight / 3)
695 			return ret;
696 	}
697 
698 	gclow = w;
699 	gcloh = h;
700 	gclox = dx;
701 	gcloy = dy;
702 	gclorealh = *prealh;
703 	*pw = w;
704 	*ph = h;
705 	*pdx = dx;
706 	*pdy = dy;
707 #if 1
708 	write_log (_T("Display Size: %dx%d Offset: %dx%d\n"), w, h, dx, dy);
709 	write_log (_T("First: %d Last: %d MinV: %d MaxV: %d Min: %d\n"),
710 		plffirstline_total, plflastline_total,
711 		first_planes_vpos, last_planes_vpos, minfirstline);
712 #endif
713 	center_reset = true;
714 	return 1;
715 }
716 
get_custom_mouse_limits(int * pw,int * ph,int * pdx,int * pdy,int dbl)717 void get_custom_mouse_limits (int *pw, int *ph, int *pdx, int *pdy, int dbl)
718 {
719 	int delay1, delay2;
720 	int w, h, dx, dy, dbl1, dbl2, y1, y2;
721 
722 	w = diwlastword_total - diwfirstword_total;
723 	dx = diwfirstword_total - visible_left_border;
724 
725 	y2 = plflastline_total;
726 	if (y2 > last_planes_vpos)
727 		y2 = last_planes_vpos;
728 	y1 = plffirstline_total;
729 	if (first_planes_vpos > y1)
730 		y1 = first_planes_vpos;
731 	if (minfirstline > y1)
732 		y1 = minfirstline;
733 
734 	h = y2 - y1;
735 	dy = y1 - minfirstline;
736 
737 	if (*pw > 0)
738 		w = *pw;
739 
740 	w = xshift (w, res_shift);
741 
742 	if (*ph > 0)
743 		h = *ph;
744 
745 	delay1 = (firstword_bplcon1 & 0x0f) | ((firstword_bplcon1 & 0x0c00) >> 6);
746 	delay2 = ((firstword_bplcon1 >> 4) & 0x0f) | (((firstword_bplcon1 >> 4) & 0x0c00) >> 6);
747 //	if (delay1 == delay2)
748 //		dx += delay1;
749 
750 	dx = xshift (dx, res_shift);
751 
752 	dbl2 = dbl1 = currprefs.gfx_vresolution;
753 	if ((doublescan > 0 || interlace_seen > 0) && !dbl) {
754 		dbl1--;
755 		dbl2--;
756 	}
757 	if (interlace_seen > 0)
758 		dbl2++;
759 	if (interlace_seen <= 0 && dbl)
760 		dbl2--;
761 	h = xshift (h, dbl1);
762 	dy = xshift (dy, dbl2);
763 
764 	if (w < 1)
765 		w = 1;
766 	if (h < 1)
767 		h = 1;
768 	if (dx < 0)
769 		dx = 0;
770 	if (dy < 0)
771 		dy = 0;
772 	*pw = w; *ph = h;
773 	*pdx = dx; *pdy = dy;
774 }
775 
776 static struct decision *dp_for_drawing;
777 static struct draw_info *dip_for_drawing;
778 
779 /* Record DIW of the current line for use by centering code.  */
record_diw_line(int plfstrt,int first,int last)780 void record_diw_line (int plfstrt, int first, int last)
781 {
782 	if (last > max_diwstop)
783 		max_diwstop = last;
784 	if (first < min_diwstart) {
785 		min_diwstart = first;
786 		/*
787 		if (plfstrt * 2 > min_diwstart)
788 		min_diwstart = plfstrt * 2;
789 		*/
790 	}
791 }
792 
get_shdelay_add(void)793 STATIC_INLINE int get_shdelay_add(void)
794 {
795 	if (bplres == RES_SUPERHIRES)
796 		return 0;
797 	int add = bpldelay_sh;
798 	add >>= RES_MAX - currprefs.gfx_resolution;
799 	return add;
800 }
801 
802 /*
803 * Screen update macros/functions
804 */
805 
806 /* The important positions in the line: where do we start drawing the left border,
807 where do we start drawing the playfield, where do we start drawing the right border.
808 All of these are forced into the visible window (VISIBLE_LEFT_BORDER .. VISIBLE_RIGHT_BORDER).
809 PLAYFIELD_START and PLAYFIELD_END are in window coordinates.  */
810 static int playfield_start, playfield_end;
811 static int real_playfield_start, real_playfield_end;
812 static int sprite_playfield_start;
813 static bool may_require_hard_way;
814 static int linetoscr_diw_start, linetoscr_diw_end;
815 static int native_ddf_left, native_ddf_right;
816 
817 static int pixels_offset;
818 static int src_pixel;
819 /* How many pixels in window coordinates which are to the left of the left border.  */
820 static int unpainted;
821 
getbgc(bool blank)822 STATIC_INLINE xcolnr getbgc (bool blank)
823 {
824 #if BG_COLOR_DEBUG
825 	if (blank)
826 		return xcolors[0x088];
827 	else if (hposblank == 1)
828 		return xcolors[0xf00];
829 	else if (hposblank == 2)
830 		return xcolors[0x0f0];
831 	else if (hposblank == 3)
832 		return xcolors[0x00f];
833 	else if (ce_is_borderblank(colors_for_drawing.extra))
834 		return xcolors[0x880];
835 	//return colors_for_drawing.acolors[0];
836 	return xcolors[0xf0f];
837 #endif
838 	return (blank || hposblank || ce_is_borderblank(colors_for_drawing.extra)) ? 0 : colors_for_drawing.acolors[0];
839 }
840 
841 
set_res_shift(int shift)842 static void set_res_shift(int shift)
843 {
844 	int old = res_shift;
845 	res_shift = shift;
846 	if (res_shift != old)
847 		pfield_set_linetoscr();
848 }
849 
850 /* Initialize the variables necessary for drawing a line.
851 * This involves setting up start/stop positions and display window
852 * borders.  */
pfield_init_linetoscr(bool border)853 static void pfield_init_linetoscr (bool border)
854 {
855 	/* First, get data fetch start/stop in DIW coordinates.  */
856 	int ddf_left = dp_for_drawing->plfleft * 2 + DIW_DDF_OFFSET;
857 	int ddf_right = dp_for_drawing->plfright * 2 + DIW_DDF_OFFSET;
858 	int leftborderhidden;
859 	int native_ddf_left2;
860 
861 	if (border)
862 		ddf_left = DISPLAY_LEFT_SHIFT;
863 
864 	/* Compute datafetch start/stop in pixels; native display coordinates.  */
865 	native_ddf_left = coord_hw_to_window_x (ddf_left);
866 	native_ddf_right = coord_hw_to_window_x (ddf_right);
867 
868 	// Blerkenwiegel/Scoopex workaround
869 	native_ddf_left2 = native_ddf_left;
870 	if (native_ddf_left < 0)
871 		native_ddf_left = 0;
872 
873 	if (native_ddf_right < native_ddf_left)
874 		native_ddf_right = native_ddf_left;
875 
876 	linetoscr_diw_start = dp_for_drawing->diwfirstword;
877 	linetoscr_diw_end = dp_for_drawing->diwlastword;
878 
879 	/* Perverse cases happen. */
880 	if (linetoscr_diw_end < linetoscr_diw_start)
881 		linetoscr_diw_end = linetoscr_diw_start;
882 
883 	set_res_shift(lores_shift - bplres);
884 
885 	playfield_start = linetoscr_diw_start;
886 	playfield_end = linetoscr_diw_end;
887 
888 	if (playfield_start < native_ddf_left)
889 		playfield_start = native_ddf_left;
890 	if (playfield_end > native_ddf_right)
891 		playfield_end = native_ddf_right;
892 
893 	if (playfield_start < visible_left_border)
894 		playfield_start = visible_left_border;
895 	if (playfield_start > visible_right_border)
896 		playfield_start = visible_right_border;
897 	if (playfield_end < visible_left_border)
898 		playfield_end = visible_left_border;
899 	if (playfield_end > visible_right_border)
900 		playfield_end = visible_right_border;
901 
902 	real_playfield_start = playfield_start;
903 	sprite_playfield_start = playfield_start;
904 	real_playfield_end = playfield_end;
905 
906 	// Sprite hpos don't include DIW_DDF_OFFSET and can appear 1 lores pixel
907 	// before first bitplane pixel appears.
908 	// This means "bordersprite" condition is possible under OCS/ECS too. Argh!
909 	if (dip_for_drawing->nr_sprites) {
910 		if (!ce_is_borderblank(colors_for_drawing.extra)) {
911 			/* bordersprite off or not supported: sprites are visible until diw_end */
912 			if (playfield_end < linetoscr_diw_end && hblank_right_stop > playfield_end) {
913 				playfield_end = linetoscr_diw_end;
914 			}
915 			int left = coord_hw_to_window_x (dp_for_drawing->plfleft * 2);
916 			if (left < visible_left_border)
917 				left = visible_left_border;
918 			if (left < playfield_start && left >= linetoscr_diw_start) {
919 				playfield_start = left;
920 			}
921 		} else {
922 			sprite_playfield_start = 0;
923 			if (playfield_end < linetoscr_diw_end && hblank_right_stop > playfield_end) {
924 				playfield_end = linetoscr_diw_end;
925 			}
926 		}
927 	}
928 
929 #ifdef AGA
930 	may_require_hard_way = false;
931 	if (dp_for_drawing->bordersprite_seen && !ce_is_borderblank(colors_for_drawing.extra) && dip_for_drawing->nr_sprites) {
932 		int min = visible_right_border, max = visible_left_border, i;
933 		for (i = 0; i < dip_for_drawing->nr_sprites; i++) {
934 			int x;
935 			x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].pos;
936 			if (x < min)
937 				min = x;
938 			// include max extra pixels, sprite may be 2x or 4x size: 4x - 1.
939 			x = curr_sprite_entries[dip_for_drawing->first_sprite_entry + i].max + (4 - 1);
940 			if (x > max)
941 				max = x;
942 		}
943 		min = coord_hw_to_window_x (min >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift);
944 		max = coord_hw_to_window_x (max >> sprite_buffer_res) + (DIW_DDF_OFFSET << lores_shift);
945 
946 		if (min < playfield_start)
947 			playfield_start = min;
948 		if (playfield_start < visible_left_border)
949 			playfield_start = visible_left_border;
950 		if (max > playfield_end)
951 			playfield_end = max;
952 		if (playfield_end > visible_right_border)
953 			playfield_end = visible_right_border;
954 		sprite_playfield_start = 0;
955 		may_require_hard_way = true;
956 	}
957 #endif
958 
959 	unpainted = visible_left_border < playfield_start ? 0 : visible_left_border - playfield_start;
960 	unpainted = res_shift_from_window (unpainted);
961 
962 	int first_x = sprite_first_x;
963 	int last_x = sprite_last_x;
964 	if (first_x < last_x) {
965 		if (dp_for_drawing->bordersprite_seen && !ce_is_borderblank(colors_for_drawing.extra)) {
966 			if (first_x > visible_left_border)
967 				first_x = visible_left_border;
968 			if (last_x < visible_right_border)
969 				last_x = visible_right_border;
970 		}
971 		if (first_x < 0)
972 			first_x = 0;
973 		if (last_x > MAX_PIXELS_PER_LINE - 2)
974 			last_x = MAX_PIXELS_PER_LINE - 2;
975 		if (first_x < last_x)
976 			memset (spritepixels + first_x, 0, sizeof (struct spritepixelsbuf) * (last_x - first_x + 1));
977 	}
978 
979 	sprite_last_x = 0;
980 	sprite_first_x = MAX_PIXELS_PER_LINE - 1;
981 
982 	/* Now, compute some offsets.  */
983 	ddf_left -= DISPLAY_LEFT_SHIFT;
984 	pixels_offset = MAX_PIXELS_PER_LINE - (ddf_left << bplres);
985 	ddf_left <<= bplres;
986 
987 	leftborderhidden = playfield_start - native_ddf_left2;
988 	if (hblank_left_start > playfield_start)
989 		leftborderhidden += hblank_left_start - playfield_start;
990 	src_pixel = MAX_PIXELS_PER_LINE + res_shift_from_window (leftborderhidden);
991 
992 	if (dip_for_drawing->nr_sprites == 0)
993 		return;
994 
995 	if (aga_mode) {
996 		int add = get_shdelay_add();
997 		if (add) {
998 			if (sprite_playfield_start > 0) {
999 				sprite_playfield_start -= add;
1000 			} else {
1001 				playfield_start -= add;
1002 			}
1003 		}
1004 	}
1005 
1006 	/* We need to clear parts of apixels.  */
1007 	if (linetoscr_diw_start < native_ddf_left) {
1008 		int size = res_shift_from_window (native_ddf_left - linetoscr_diw_start);
1009 		linetoscr_diw_start = native_ddf_left;
1010 		memset (pixdata.apixels + MAX_PIXELS_PER_LINE - size, 0, size);
1011 	}
1012 	if (linetoscr_diw_end > native_ddf_right) {
1013 		int pos = res_shift_from_window (native_ddf_right - native_ddf_left);
1014 		int size = res_shift_from_window (linetoscr_diw_end - native_ddf_right);
1015 		linetoscr_diw_start = native_ddf_left;
1016 		memset (pixdata.apixels + MAX_PIXELS_PER_LINE + pos, 0, size);
1017 	}
1018 }
1019 
1020 // erase sprite graphics in pixdata if they were outside of ddf
pfield_erase_hborder_sprites(void)1021 static void pfield_erase_hborder_sprites (void)
1022 {
1023 	if (sprite_first_x < native_ddf_left) {
1024 		int size = res_shift_from_window (native_ddf_left - sprite_first_x);
1025 		memset (pixdata.apixels + MAX_PIXELS_PER_LINE - size, 0, size);
1026 	}
1027 	if (sprite_last_x > native_ddf_right) {
1028 		int pos = res_shift_from_window (native_ddf_right - native_ddf_left);
1029 		int size = res_shift_from_window (sprite_last_x - native_ddf_right);
1030 		memset (pixdata.apixels + MAX_PIXELS_PER_LINE + pos, 0, size);
1031 	}
1032 }
1033 
1034 // erase whole viewable area if sprite in upper or lower border
pfield_erase_vborder_sprites(void)1035 static void pfield_erase_vborder_sprites (void)
1036 {
1037 	if (visible_right_border <= visible_left_border)
1038 		return;
1039 	int pos = 0;
1040 	int size = 0;
1041 	if (visible_left_border < native_ddf_left) {
1042 		size = res_shift_from_window (native_ddf_left - visible_left_border);
1043 		pos = -size;
1044 	}
1045 	if (visible_right_border > native_ddf_left)
1046 		size += res_shift_from_window (visible_right_border - native_ddf_left);
1047 	memset (pixdata.apixels + MAX_PIXELS_PER_LINE - pos, 0, size);
1048 }
1049 
1050 
merge_2pixel16(uae_u16 p1,uae_u16 p2)1051 STATIC_INLINE uae_u16 merge_2pixel16 (uae_u16 p1, uae_u16 p2)
1052 {
1053 	uae_u16 v = ((((p1 >> xredcolor_s) & xredcolor_m) + ((p2 >> xredcolor_s) & xredcolor_m)) / 2) << xredcolor_s;
1054 	v |= ((((p1 >> xbluecolor_s) & xbluecolor_m) + ((p2 >> xbluecolor_s) & xbluecolor_m)) / 2) << xbluecolor_s;
1055 	v |= ((((p1 >> xgreencolor_s) & xgreencolor_m) + ((p2 >> xgreencolor_s) & xgreencolor_m)) / 2) << xgreencolor_s;
1056 	return v;
1057 }
merge_2pixel32(uae_u32 p1,uae_u32 p2)1058 STATIC_INLINE uae_u32 merge_2pixel32 (uae_u32 p1, uae_u32 p2)
1059 {
1060 	uae_u32 v = ((((p1 >> 16) & 0xff) + ((p2 >> 16) & 0xff)) / 2) << 16;
1061 	v |= ((((p1 >> 8) & 0xff) + ((p2 >> 8) & 0xff)) / 2) << 8;
1062 	v |= ((((p1 >> 0) & 0xff) + ((p2 >> 0) & 0xff)) / 2) << 0;
1063 	return v;
1064 }
1065 
fill_line_16(uae_u8 * buf,int start,int stop,bool blank)1066 STATIC_INLINE void fill_line_16 (uae_u8 *buf, int start, int stop, bool blank)
1067 {
1068 	uae_u16 *b = (uae_u16 *)buf;
1069 	unsigned int i;
1070 	unsigned int rem = 0;
1071 	xcolnr col = getbgc (blank);
1072 	if (((uintptr_t)&b[start]) & 1)
1073 		b[start++] = (uae_u16) col;
1074 	if (start >= stop)
1075 		return;
1076 	if (((uintptr_t)&b[stop]) & 1) {
1077 		rem++;
1078 		stop--;
1079 	}
1080 	for (i = start; i < stop; i += 2) {
1081 		uae_u32 *b2 = (uae_u32 *)&b[i];
1082 		*b2 = col;
1083 	}
1084 	if (rem)
1085 		b[stop] = (uae_u16)col;
1086 }
1087 
fill_line_32(uae_u8 * buf,int start,int stop,bool blank)1088 STATIC_INLINE void fill_line_32 (uae_u8 *buf, int start, int stop, bool blank)
1089 {
1090 	uae_u32 *b = (uae_u32 *)buf;
1091 	unsigned int i;
1092 	xcolnr col = getbgc (blank);
1093 	for (i = start; i < stop; i++)
1094 		b[i] = col;
1095 }
1096 
pfield_do_fill_line(int start,int stop,bool blank)1097 static void pfield_do_fill_line (int start, int stop, bool blank)
1098 {
1099 	switch (gfxvidinfo.drawbuffer.pixbytes) {
1100 	case 2: fill_line_16 (xlinebuffer, start, stop, blank); break;
1101 	case 4: fill_line_32 (xlinebuffer, start, stop, blank); break;
1102 	}
1103 	if (need_genlock_data) {
1104 		memset(xlinebuffer_genlock + start, 0, stop - start);
1105 	}
1106 }
1107 
fill_line2(int startpos,int len)1108 static void fill_line2 (int startpos, int len)
1109 {
1110 	int shift;
1111 	int nints, nrem;
1112 	int *start;
1113 	xcolnr val;
1114 
1115 	shift = 0;
1116 	if (gfxvidinfo.drawbuffer.pixbytes == 2)
1117 		shift = 1;
1118 	if (gfxvidinfo.drawbuffer.pixbytes == 4)
1119 		shift = 2;
1120 
1121 	nints = len >> (2 - shift);
1122 	nrem = nints & 7;
1123 	nints &= ~7;
1124 	start = (int *)(((uae_u8*)xlinebuffer) + (startpos << shift));
1125 	val = getbgc (false);
1126 	for (; nints > 0; nints -= 8, start += 8) {
1127 		*start = val;
1128 		*(start+1) = val;
1129 		*(start+2) = val;
1130 		*(start+3) = val;
1131 		*(start+4) = val;
1132 		*(start+5) = val;
1133 		*(start+6) = val;
1134 		*(start+7) = val;
1135 	}
1136 
1137 	switch (nrem) {
1138 	case 7:
1139 		*start++ = val;
1140 	case 6:
1141 		*start++ = val;
1142 	case 5:
1143 		*start++ = val;
1144 	case 4:
1145 		*start++ = val;
1146 	case 3:
1147 		*start++ = val;
1148 	case 2:
1149 		*start++ = val;
1150 	case 1:
1151 		*start = val;
1152 	}
1153 }
1154 
fill_line_border(int lineno)1155 static void fill_line_border (int lineno)
1156 {
1157 	int lastpos = visible_left_border;
1158 	int endpos = visible_left_border + gfxvidinfo.drawbuffer.inwidth;
1159 
1160 	if (lineno < visible_top_start || lineno >= visible_bottom_stop) {
1161 		int b = hposblank;
1162 		hposblank = 3;
1163 		fill_line2(lastpos, gfxvidinfo.drawbuffer.inwidth);
1164 		if (need_genlock_data) {
1165 			memset(xlinebuffer_genlock + lastpos, 0, gfxvidinfo.drawbuffer.inwidth);
1166 		}
1167 		hposblank = b;
1168 		return;
1169 	}
1170 
1171 	// full hblank
1172 	if (hposblank) {
1173 		hposblank = 3;
1174 		fill_line2(lastpos, gfxvidinfo.drawbuffer.inwidth);
1175 		if (need_genlock_data) {
1176 			memset(xlinebuffer_genlock + lastpos, 0, gfxvidinfo.drawbuffer.inwidth);
1177 		}
1178 		return;
1179 	}
1180 	// hblank not visible
1181 	if (hblank_left_start <= lastpos && hblank_right_stop >= endpos) {
1182 		fill_line2(lastpos, gfxvidinfo.drawbuffer.inwidth);
1183 		if (need_genlock_data) {
1184 			memset(xlinebuffer_genlock + lastpos, 0, gfxvidinfo.drawbuffer.inwidth);
1185 		}
1186 		return;
1187 	}
1188 
1189 	// left, right or both hblanks visible
1190 	if (lastpos < hblank_left_start) {
1191 		int t = hblank_left_start < endpos ? hblank_left_start : endpos;
1192 		pfield_do_fill_line(lastpos, t, true);
1193 		lastpos = t;
1194 	}
1195 	if (lastpos < hblank_right_stop) {
1196 		int t = hblank_right_stop < endpos ? hblank_right_stop : endpos;
1197 		pfield_do_fill_line(lastpos, t, false);
1198 		lastpos = t;
1199 	}
1200 	if (lastpos < endpos) {
1201 		pfield_do_fill_line(lastpos, endpos, true);
1202 	}
1203 }
1204 
1205 static int sprite_shdelay;
1206 #define SPRITE_DEBUG 0
render_sprites(int pos,int dualpf,uae_u8 apixel,int aga)1207 static uae_u8 render_sprites (int pos, int dualpf, uae_u8 apixel, int aga)
1208 {
1209 	struct spritepixelsbuf *spb = &spritepixels[pos];
1210 	unsigned int v = spb->data;
1211 	int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms;
1212 	int maskshift, plfmask;
1213 
1214 	// shdelay hack, above &spritepixels[pos] is correct.
1215 	pos += sprite_shdelay;
1216 	/* The value in the shift lookup table is _half_ the shift count we
1217 	need.  This is because we can't shift 32 bits at once (undefined
1218 	behaviour in C).  */
1219 	maskshift = shift_lookup[apixel];
1220 	plfmask = (plf_sprite_mask >> maskshift) >> maskshift;
1221 	v &= ~plfmask;
1222 	/* Extra 1 sprite pixel at DDFSTRT is only possible if at least 1 plane is active */
1223 	if ((bplplanecnt > 0 || pos >= sprite_playfield_start) && (v != 0 || SPRITE_DEBUG)) {
1224 		unsigned int vlo, vhi, col;
1225 		unsigned int v1 = v & 255;
1226 		/* OFFS determines the sprite pair with the highest priority that has
1227 		any bits set.  E.g. if we have 0xFF00 in the buffer, we have sprite
1228 		pairs 01 and 23 cleared, and pairs 45 and 67 set, so OFFS will
1229 		have a value of 4.
1230 		2 * OFFS is the bit number in V of the sprite pair, and it also
1231 		happens to be the color offset for that pair.
1232 		*/
1233 		int offs;
1234 		if (v1 == 0)
1235 			offs = 4 + sprite_offs[v >> 8];
1236 		else
1237 			offs = sprite_offs[v1];
1238 
1239 		/* Shift highest priority sprite pair down to bit zero.  */
1240 		v >>= offs * 2;
1241 		v &= 15;
1242 #if SPRITE_DEBUG > 0
1243 		v ^= 8;
1244 #endif
1245 		if (spb->attach && (spb->stdata & (3 << offs))) {
1246 			col = v;
1247 			if (aga)
1248 				col += sbasecol[1];
1249 			else
1250 				col += 16;
1251 		} else {
1252 			/* This sequence computes the correct color value.  We have to select
1253 			either the lower-numbered or the higher-numbered sprite in the pair.
1254 			We have to select the high one if the low one has all bits zero.
1255 			If the lower-numbered sprite has any bits nonzero, (VLO - 1) is in
1256 			the range of 0..2, and with the mask and shift, VHI will be zero.
1257 			If the lower-numbered sprite is zero, (VLO - 1) is a mask of
1258 			0xFFFFFFFF, and we select the bits of the higher numbered sprite
1259 			in VHI.
1260 			This is _probably_ more efficient than doing it with branches.  */
1261 			vlo = v & 3;
1262 			vhi = (v & (vlo - 1)) >> 2;
1263 			col = (vlo | vhi);
1264 			if (aga) {
1265 				if (vhi > 0)
1266 					col += sbasecol[1];
1267 				else
1268 					col += sbasecol[0];
1269 			} else {
1270 				col += 16;
1271 			}
1272 			col += offs * 2;
1273 		}
1274 
1275 		return col;
1276 	}
1277 
1278 	return 0;
1279 }
1280 
get_genlock_very_rare_and_complex_case(uae_u8 v)1281 static bool get_genlock_very_rare_and_complex_case(uae_u8 v)
1282 {
1283 	// border color without BRDNTRAN bit set = transparent
1284 	if (v == 0 && !ce_is_borderntrans(colors_for_drawing.extra))
1285 		return false;
1286 	if (ecs_genlock_features_colorkey) {
1287 		// color key match?
1288 		if (0) {
1289 #ifdef AGA
1290 		} else if (currprefs.chipset_mask & CSMASK_AGA) {
1291 			if (colors_for_drawing.color_regs_aga[v] & 0x80000000)
1292 				return false;
1293 #endif
1294 		} else {
1295 			if (colors_for_drawing.color_regs_ecs[v] & 0x8000)
1296 				return false;
1297 		}
1298 	}
1299 	// plane mask match?
1300 	if (v & ecs_genlock_features_mask)
1301 		return false;
1302 	return true;
1303 }
1304 // false = transparent
get_genlock_transparency(uae_u8 v)1305 STATIC_INLINE bool get_genlock_transparency(uae_u8 v)
1306 {
1307 	if (!ecs_genlock_features_active) {
1308 		if (v == 0)
1309 			return false;
1310 		return true;
1311 	} else {
1312 		return get_genlock_very_rare_and_complex_case(v);
1313 	}
1314 }
1315 
1316 #include "linetoscr.cpp"
1317 
1318 #define LTPARMS src_pixel, start, stop
1319 
1320 #ifdef ECS_DENISE
1321 /* ECS SuperHires special cases */
1322 
1323 #define PUTBPIX(x) buf[dpix] = (x);
1324 
shsprite(int dpix,uae_u32 spix_val,uae_u32 v,int spr)1325 STATIC_INLINE uae_u32 shsprite (int dpix, uae_u32 spix_val, uae_u32 v, int spr)
1326 {
1327 	uae_u8 sprcol;
1328 	uae_u16 scol;
1329 	if (!spr)
1330 		return v;
1331 	sprcol = render_sprites (dpix, 0, spix_val, 0);
1332 	if (!sprcol)
1333 		return v;
1334 	/* good enough for now.. */
1335 	scol = colors_for_drawing.color_regs_ecs[sprcol] & 0xccc;
1336 	scol |= scol >> 2;
1337 	return xcolors[scol];
1338 }
1339 
linetoscr_16_sh_func(int spix,int dpix,int stoppos,int spr)1340 static int NOINLINE linetoscr_16_sh_func(int spix, int dpix, int stoppos, int spr)
1341 {
1342 	uae_u16 *buf = (uae_u16 *) xlinebuffer;
1343 
1344 	while (dpix < stoppos) {
1345 		uae_u16 spix_val1, spix_val2;
1346 		uae_u16 v;
1347 		int off;
1348 		spix_val1 = pixdata.apixels[spix++];
1349 		spix_val2 = pixdata.apixels[spix++];
1350 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1351 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1352 		v |= v >> 2;
1353 		PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
1354 		dpix++;
1355 		v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
1356 		v |= v >> 2;
1357 		PUTBPIX(shsprite (dpix, spix_val2, xcolors[v], spr));
1358 		dpix++;
1359 	}
1360 	return spix;
1361 }
linetoscr_16_sh_spr(int spix,int dpix,int stoppos)1362 static int linetoscr_16_sh_spr(int spix, int dpix, int stoppos)
1363 {
1364 	return linetoscr_16_sh_func(spix, dpix, stoppos, true);
1365 }
linetoscr_16_sh(int spix,int dpix,int stoppos)1366 static int linetoscr_16_sh(int spix, int dpix, int stoppos)
1367 {
1368 	return linetoscr_16_sh_func(spix, dpix, stoppos, false);
1369 }
linetoscr_32_sh_func(int spix,int dpix,int stoppos,int spr)1370 static int NOINLINE linetoscr_32_sh_func(int spix, int dpix, int stoppos, int spr)
1371 {
1372 	uae_u32 *buf = (uae_u32 *) xlinebuffer;
1373 
1374 	while (dpix < stoppos) {
1375 		uae_u32 spix_val1, spix_val2;
1376 		uae_u16 v;
1377 		int off;
1378 		spix_val1 = pixdata.apixels[spix++];
1379 		spix_val2 = pixdata.apixels[spix++];
1380 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1381 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1382 		v |= v >> 2;
1383 		PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
1384 		dpix++;
1385 		v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
1386 		v |= v >> 2;
1387 		PUTBPIX(shsprite (dpix, spix_val2, xcolors[v], spr));
1388 		dpix++;
1389 	}
1390 	return spix;
1391 }
linetoscr_32_sh_spr(int spix,int dpix,int stoppos)1392 static int linetoscr_32_sh_spr(int spix, int dpix, int stoppos)
1393 {
1394 	return linetoscr_32_sh_func(spix, dpix, stoppos, true);
1395 }
linetoscr_32_sh(int spix,int dpix,int stoppos)1396 static int linetoscr_32_sh(int spix, int dpix, int stoppos)
1397 {
1398 	return linetoscr_32_sh_func(spix, dpix, stoppos, false);
1399 }
linetoscr_32_shrink1_sh_func(int spix,int dpix,int stoppos,int spr)1400 static int NOINLINE linetoscr_32_shrink1_sh_func(int spix, int dpix, int stoppos, int spr)
1401 {
1402 	uae_u32 *buf = (uae_u32 *) xlinebuffer;
1403 
1404 	while (dpix < stoppos) {
1405 		uae_u32 spix_val1, spix_val2;
1406 		uae_u16 v;
1407 		int off;
1408 		spix_val1 = pixdata.apixels[spix++];
1409 		spix_val2 = pixdata.apixels[spix++];
1410 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1411 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1412 		v |= v >> 2;
1413 		PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
1414 		dpix++;
1415 	}
1416 	return spix;
1417 }
linetoscr_32_shrink1_sh_spr(int spix,int dpix,int stoppos)1418 static int linetoscr_32_shrink1_sh_spr(int spix, int dpix, int stoppos)
1419 {
1420 	return linetoscr_32_shrink1_sh_func(spix, dpix, stoppos, true);
1421 }
linetoscr_32_shrink1_sh(int spix,int dpix,int stoppos)1422 static int linetoscr_32_shrink1_sh(int spix, int dpix, int stoppos)
1423 {
1424 	return linetoscr_32_shrink1_sh_func(spix, dpix, stoppos, false);
1425 }
linetoscr_32_shrink1f_sh_func(int spix,int dpix,int stoppos,int spr)1426 static int NOINLINE linetoscr_32_shrink1f_sh_func(int spix, int dpix, int stoppos, int spr)
1427 {
1428 	uae_u32 *buf = (uae_u32 *) xlinebuffer;
1429 
1430 	while (dpix < stoppos) {
1431 		uae_u32 spix_val1, spix_val2, dpix_val1, dpix_val2;
1432 		uae_u16 v;
1433 		int off;
1434 		spix_val1 = pixdata.apixels[spix++];
1435 		spix_val2 = pixdata.apixels[spix++];
1436 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1437 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1438 		v |= v >> 2;
1439 		dpix_val1 = xcolors[v];
1440 		v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
1441 		v |= v >> 2;
1442 		dpix_val2 = xcolors[v];
1443 		PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel32 (dpix_val1, dpix_val2), spr));
1444 		dpix++;
1445 	}
1446 	return spix;
1447 }
linetoscr_32_shrink1f_sh_spr(int spix,int dpix,int stoppos)1448 static int linetoscr_32_shrink1f_sh_spr(int spix, int dpix, int stoppos)
1449 {
1450 	return linetoscr_32_shrink1f_sh_func(spix, dpix, stoppos, true);
1451 }
linetoscr_32_shrink1f_sh(int spix,int dpix,int stoppos)1452 static int linetoscr_32_shrink1f_sh(int spix, int dpix, int stoppos)
1453 {
1454 	return linetoscr_32_shrink1f_sh_func(spix, dpix, stoppos, false);
1455 }
linetoscr_16_shrink1_sh_func(int spix,int dpix,int stoppos,int spr)1456 static int NOINLINE linetoscr_16_shrink1_sh_func(int spix, int dpix, int stoppos, int spr)
1457 {
1458 	uae_u16 *buf = (uae_u16 *) xlinebuffer;
1459 
1460 	while (dpix < stoppos) {
1461 		uae_u16 spix_val1, spix_val2;
1462 		uae_u16 v;
1463 		int off;
1464 		spix_val1 = pixdata.apixels[spix++];
1465 		spix_val2 = pixdata.apixels[spix++];
1466 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1467 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1468 		v |= v >> 2;
1469 		PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
1470 		dpix++;
1471 	}
1472 	return spix;
1473 }
linetoscr_16_shrink1_sh_spr(int spix,int dpix,int stoppos)1474 static int linetoscr_16_shrink1_sh_spr(int spix, int dpix, int stoppos)
1475 {
1476 	return linetoscr_16_shrink1_sh_func(spix, dpix, stoppos, true);
1477 }
linetoscr_16_shrink1_sh(int spix,int dpix,int stoppos)1478 static int linetoscr_16_shrink1_sh(int spix, int dpix, int stoppos)
1479 {
1480 	return linetoscr_16_shrink1_sh_func(spix, dpix, stoppos, false);
1481 }
linetoscr_16_shrink1f_sh_func(int spix,int dpix,int stoppos,int spr)1482 static int NOINLINE linetoscr_16_shrink1f_sh_func(int spix, int dpix, int stoppos, int spr)
1483 {
1484 	uae_u16 *buf = (uae_u16 *) xlinebuffer;
1485 
1486 	while (dpix < stoppos) {
1487 		uae_u16 spix_val1, spix_val2, dpix_val1, dpix_val2;
1488 		uae_u16 v;
1489 		int off;
1490 		spix_val1 = pixdata.apixels[spix++];
1491 		spix_val2 = pixdata.apixels[spix++];
1492 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1493 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1494 		v |= v >> 2;
1495 		dpix_val1 = xcolors[v];
1496 		v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
1497 		v |= v >> 2;
1498 		dpix_val2 = xcolors[v];
1499 		PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel16 (dpix_val1, dpix_val2), spr));
1500 		dpix++;
1501 	}
1502 	return spix;
1503 }
linetoscr_16_shrink1f_sh_spr(int spix,int dpix,int stoppos)1504 static int linetoscr_16_shrink1f_sh_spr(int spix, int dpix, int stoppos)
1505 {
1506 	return linetoscr_16_shrink1f_sh_func(spix, dpix, stoppos, true);
1507 }
linetoscr_16_shrink1f_sh(int spix,int dpix,int stoppos)1508 static int linetoscr_16_shrink1f_sh(int spix, int dpix, int stoppos)
1509 {
1510 	return linetoscr_16_shrink1f_sh_func(spix, dpix, stoppos, false);
1511 }
linetoscr_32_shrink2_sh_func(int spix,int dpix,int stoppos,int spr)1512 static int NOINLINE linetoscr_32_shrink2_sh_func(int spix, int dpix, int stoppos, int spr)
1513 {
1514 	uae_u32 *buf = (uae_u32 *) xlinebuffer;
1515 
1516 	while (dpix < stoppos) {
1517 		uae_u32 spix_val1, spix_val2;
1518 		uae_u16 v;
1519 		int off;
1520 		spix_val1 = pixdata.apixels[spix++];
1521 		spix_val2 = pixdata.apixels[spix++];
1522 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1523 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1524 		v |= v >> 2;
1525 		PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
1526 		spix+=2;
1527 		dpix++;
1528 	}
1529 	return spix;
1530 }
linetoscr_32_shrink2_sh_spr(int spix,int dpix,int stoppos)1531 static int linetoscr_32_shrink2_sh_spr(int spix, int dpix, int stoppos)
1532 {
1533 	return linetoscr_32_shrink2_sh_func(spix, dpix, stoppos, true);
1534 }
linetoscr_32_shrink2_sh(int spix,int dpix,int stoppos)1535 static int linetoscr_32_shrink2_sh(int spix, int dpix, int stoppos)
1536 {
1537 	return linetoscr_32_shrink2_sh_func(spix, dpix, stoppos, false);
1538 }
linetoscr_32_shrink2f_sh_func(int spix,int dpix,int stoppos,int spr)1539 static int NOINLINE linetoscr_32_shrink2f_sh_func(int spix, int dpix, int stoppos, int spr)
1540 {
1541 	uae_u32 *buf = (uae_u32 *) xlinebuffer;
1542 
1543 	while (dpix < stoppos) {
1544 		uae_u32 spix_val1, spix_val2, dpix_val1, dpix_val2, dpix_val3, dpix_val4;
1545 		uae_u16 v;
1546 		int off;
1547 		spix_val1 = pixdata.apixels[spix++];
1548 		spix_val2 = pixdata.apixels[spix++];
1549 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1550 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1551 		v |= v >> 2;
1552 		dpix_val1 = xcolors[v];
1553 		v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
1554 		v |= v >> 2;
1555 		dpix_val2 = xcolors[v];
1556 		dpix_val3 = merge_2pixel32 (dpix_val1, dpix_val2);
1557 		spix_val1 = pixdata.apixels[spix++];
1558 		spix_val2 = pixdata.apixels[spix++];
1559 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1560 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1561 		v |= v >> 2;
1562 		dpix_val1 = xcolors[v];
1563 		v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
1564 		v |= v >> 2;
1565 		dpix_val2 = xcolors[v];
1566 		dpix_val4 = merge_2pixel32 (dpix_val1, dpix_val2);
1567 		PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel32 (dpix_val3, dpix_val4), spr));
1568 		dpix++;
1569 	}
1570 	return spix;
1571 }
linetoscr_32_shrink2f_sh_spr(int spix,int dpix,int stoppos)1572 static int linetoscr_32_shrink2f_sh_spr(int spix, int dpix, int stoppos)
1573 {
1574 	return linetoscr_32_shrink2f_sh_func(spix, dpix, stoppos, true);
1575 }
linetoscr_32_shrink2f_sh(int spix,int dpix,int stoppos)1576 static int linetoscr_32_shrink2f_sh(int spix, int dpix, int stoppos)
1577 {
1578 	return linetoscr_32_shrink2f_sh_func(spix, dpix, stoppos, false);
1579 }
linetoscr_16_shrink2_sh_func(int spix,int dpix,int stoppos,int spr)1580 static int NOINLINE linetoscr_16_shrink2_sh_func(int spix, int dpix, int stoppos, int spr)
1581 {
1582 	uae_u16 *buf = (uae_u16 *) xlinebuffer;
1583 
1584 	while (dpix < stoppos) {
1585 		uae_u16 spix_val1, spix_val2;
1586 		uae_u16 v;
1587 		int off;
1588 		spix_val1 = pixdata.apixels[spix++];
1589 		spix_val2 = pixdata.apixels[spix++];
1590 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1591 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1592 		v |= v >> 2;
1593 		PUTBPIX(shsprite (dpix, spix_val1, xcolors[v], spr));
1594 		spix+=2;
1595 		dpix++;
1596 	}
1597 	return spix;
1598 }
linetoscr_16_shrink2_sh_spr(int spix,int dpix,int stoppos)1599 static int linetoscr_16_shrink2_sh_spr(int spix, int dpix, int stoppos)
1600 {
1601 	return linetoscr_16_shrink2_sh_func(spix, dpix, stoppos, true);
1602 }
linetoscr_16_shrink2_sh(int spix,int dpix,int stoppos)1603 static int linetoscr_16_shrink2_sh(int spix, int dpix, int stoppos)
1604 {
1605 	return linetoscr_16_shrink2_sh_func(spix, dpix, stoppos, false);
1606 }
linetoscr_16_shrink2f_sh_func(int spix,int dpix,int stoppos,int spr)1607 static int NOINLINE linetoscr_16_shrink2f_sh_func (int spix, int dpix, int stoppos, int spr)
1608 {
1609 	uae_u16 *buf = (uae_u16 *) xlinebuffer;
1610 
1611 	while (dpix < stoppos) {
1612 		uae_u16 spix_val1, spix_val2, dpix_val1, dpix_val2, dpix_val3, dpix_val4;
1613 		uae_u16 v;
1614 		int off;
1615 		spix_val1 = pixdata.apixels[spix++];
1616 		spix_val2 = pixdata.apixels[spix++];
1617 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1618 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1619 		v |= v >> 2;
1620 		dpix_val1 = xcolors[v];
1621 		v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
1622 		v |= v >> 2;
1623 		dpix_val2 = xcolors[v];
1624 		dpix_val3 = merge_2pixel32 (dpix_val1, dpix_val2);
1625 		spix_val1 = pixdata.apixels[spix++];
1626 		spix_val2 = pixdata.apixels[spix++];
1627 		off = ((spix_val2 & 3) * 4) + (spix_val1 & 3) + ((spix_val1 | spix_val2) & 16);
1628 		v = (colors_for_drawing.color_regs_ecs[off] & 0xccc) << 0;
1629 		v |= v >> 2;
1630 		dpix_val1 = xcolors[v];
1631 		v = (colors_for_drawing.color_regs_ecs[off] & 0x333) << 2;
1632 		v |= v >> 2;
1633 		dpix_val2 = xcolors[v];
1634 		dpix_val4 = merge_2pixel32 (dpix_val1, dpix_val2);
1635 		PUTBPIX(shsprite (dpix, spix_val1, merge_2pixel16 (dpix_val3, dpix_val4), spr));
1636 		dpix++;
1637 	}
1638 	return spix;
1639 }
linetoscr_16_shrink2f_sh_spr(int spix,int dpix,int stoppos)1640 static int linetoscr_16_shrink2f_sh_spr(int spix, int dpix, int stoppos)
1641 {
1642 	return linetoscr_16_shrink2f_sh_func(spix, dpix, stoppos, true);
1643 }
linetoscr_16_shrink2f_sh(int spix,int dpix,int stoppos)1644 static int linetoscr_16_shrink2f_sh(int spix, int dpix, int stoppos)
1645 {
1646 	return linetoscr_16_shrink2f_sh_func(spix, dpix, stoppos, false);
1647 }
1648 #endif
1649 
1650 typedef int(*call_linetoscr)(int spix, int dpix, int dpix_end);
1651 
1652 static call_linetoscr pfield_do_linetoscr_normal;
1653 static call_linetoscr pfield_do_linetoscr_sprite;
1654 static call_linetoscr pfield_do_linetoscr_spriteonly;
1655 
pfield_do_linetoscr(int start,int stop,bool blank)1656 static void pfield_do_linetoscr(int start, int stop, bool blank)
1657 {
1658 	src_pixel = pfield_do_linetoscr_normal(src_pixel, start, stop);
1659 }
pfield_do_linetoscr_spr(int start,int stop,bool blank)1660 static void pfield_do_linetoscr_spr(int start, int stop, bool blank)
1661 {
1662 	src_pixel = pfield_do_linetoscr_sprite(src_pixel, start, stop);
1663 }
pfield_do_nothing(int a,int b,int c)1664 static int pfield_do_nothing(int a, int b, int c)
1665 {
1666 	return a;
1667 }
1668 
1669 /* AGA subpixel delay hack */
1670 static call_linetoscr pfield_do_linetoscr_shdelay_normal;
1671 static call_linetoscr pfield_do_linetoscr_shdelay_sprite;
1672 
pfield_do_linetoscr_normal_shdelay(int spix,int dpix,int dpix_end)1673 static int pfield_do_linetoscr_normal_shdelay(int spix, int dpix, int dpix_end)
1674 {
1675 	int add = get_shdelay_add();
1676 	int add2 = add * gfxvidinfo.drawbuffer.pixbytes;
1677 	if (add) {
1678 		// Clear skipped pixel(s).
1679 		pfield_do_linetoscr_shdelay_sprite(spix, dpix, dpix + add);
1680 	}
1681 	xlinebuffer += add2;
1682 	int out = pfield_do_linetoscr_shdelay_normal(spix, dpix, dpix_end);
1683 	xlinebuffer -= add2;
1684 	return out;
1685 }
pfield_do_linetoscr_sprite_shdelay(int spix,int dpix,int dpix_end)1686 static int pfield_do_linetoscr_sprite_shdelay(int spix, int dpix, int dpix_end)
1687 {
1688 	int out = spix;
1689 	if (dpix < real_playfield_start && dpix_end > real_playfield_start) {
1690 		// Crosses real_playfield_start.
1691 		// Render only from dpix to real_playfield_start.
1692 		int len = real_playfield_start - dpix;
1693 		out = pfield_do_linetoscr_spriteonly(out, dpix, dpix + len);
1694 		dpix = real_playfield_start;
1695 	} else if (dpix_end <= real_playfield_start) {
1696 		// Does not cross real_playfield_start, nothing special needed.
1697 		out = pfield_do_linetoscr_spriteonly(out, dpix, dpix_end);
1698 		return out;
1699 	}
1700 	// Render bitplane with subpixel scroll, from real_playfield_start to end.
1701 	int add = get_shdelay_add();
1702 	int add2 = add * gfxvidinfo.drawbuffer.pixbytes;
1703 	if (add) {
1704 		pfield_do_linetoscr_shdelay_sprite(out, dpix, dpix + add);
1705 	}
1706 	sprite_shdelay = add;
1707 	spritepixels += add;
1708 	xlinebuffer += add2;
1709 	out = pfield_do_linetoscr_shdelay_sprite(out, dpix, dpix_end);
1710 	xlinebuffer -= add2;
1711 	spritepixels -= add;
1712 	sprite_shdelay = 0;
1713 	return out;
1714 }
1715 
pfield_set_linetoscr(void)1716 static void pfield_set_linetoscr (void)
1717 {
1718 	xlinecheck(start, stop);
1719 	spritepixels = spritepixels_buffer;
1720 	pfield_do_linetoscr_spriteonly = pfield_do_nothing;
1721 #ifdef AGA
1722 	if (currprefs.chipset_mask & CSMASK_AGA) {
1723 		if (res_shift == 0) {
1724 			switch (gfxvidinfo.drawbuffer.pixbytes) {
1725 				case 2:
1726 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_aga_genlock : linetoscr_16_aga;
1727 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_aga_spr_genlock : linetoscr_16_aga_spr;
1728 				pfield_do_linetoscr_spriteonly = linetoscr_16_aga_spronly;
1729 				break;
1730 				case 4:
1731 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_aga_genlock : linetoscr_32_aga;
1732 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_aga_spr_genlock : linetoscr_32_aga_spr;
1733 				pfield_do_linetoscr_spriteonly = linetoscr_32_aga_spronly;
1734 				break;
1735 			}
1736 		} else if (res_shift == 2) {
1737 			switch (gfxvidinfo.drawbuffer.pixbytes) {
1738 				case 2:
1739 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch2_aga_genlock : linetoscr_16_stretch2_aga;
1740 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch2_aga_spr_genlock : linetoscr_16_stretch2_aga_spr_genlock;
1741 				pfield_do_linetoscr_spriteonly = linetoscr_16_stretch2_aga_spronly;
1742 				break;
1743 				case 4:
1744 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_stretch2_aga_genlock : linetoscr_32_stretch2_aga;
1745 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_stretch2_aga_spr_genlock : linetoscr_32_stretch2_aga_spr;
1746 				pfield_do_linetoscr_spriteonly = linetoscr_32_stretch2_aga_spronly;
1747 				break;
1748 			}
1749 		} else if (res_shift == 1) {
1750 			switch (gfxvidinfo.drawbuffer.pixbytes) {
1751 				case 2:
1752 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch1_aga_genlock : linetoscr_16_stretch1_aga;
1753 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch1_aga_spr_genlock : linetoscr_16_stretch1_aga_spr;
1754 				pfield_do_linetoscr_spriteonly = linetoscr_16_stretch1_aga_spronly;
1755 				break;
1756 				case 4:
1757 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_stretch1_aga_genlock : linetoscr_32_stretch1_aga;
1758 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_stretch1_aga_spr_genlock : linetoscr_32_stretch1_aga_spr;
1759 				pfield_do_linetoscr_spriteonly = linetoscr_32_stretch1_aga_spronly;
1760 				break;
1761 			}
1762 		} else if (res_shift == -1) {
1763 			if (currprefs.gfx_lores_mode) {
1764 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1765 					case 2:
1766 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink1f_aga_genlock : linetoscr_16_shrink1f_aga;
1767 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink1f_aga_spr_genlock : linetoscr_16_shrink1f_aga_spr;
1768 					pfield_do_linetoscr_spriteonly = linetoscr_16_shrink1f_aga_spronly;
1769 					break;
1770 					case 4:
1771 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink1f_aga_genlock : linetoscr_32_shrink1f_aga;
1772 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink1f_aga_spr_genlock : linetoscr_32_shrink1f_aga_spr;
1773 					pfield_do_linetoscr_spriteonly = linetoscr_32_shrink1f_aga_spronly;
1774 					break;
1775 				}
1776 			} else {
1777 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1778 					case 2:
1779 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink1_aga_genlock : linetoscr_16_shrink1_aga;
1780 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink1_aga_spr_genlock : linetoscr_16_shrink1_aga_spr;
1781 					pfield_do_linetoscr_spriteonly = linetoscr_16_shrink1_aga_spronly;
1782 					break;
1783 					case 4:
1784 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink1_aga_genlock : linetoscr_32_shrink1_aga;
1785 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink1_aga_spr_genlock : linetoscr_32_shrink1_aga_spr;
1786 					pfield_do_linetoscr_spriteonly = linetoscr_32_shrink1_aga_spronly;
1787 					break;
1788 				}
1789 			}
1790 		} else if (res_shift == -2) {
1791 			if (currprefs.gfx_lores_mode) {
1792 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1793 					case 2:
1794 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink2f_aga_genlock : linetoscr_16_shrink2f_aga;
1795 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink2f_aga_spr_genlock : linetoscr_16_shrink2f_aga_spr;
1796 					pfield_do_linetoscr_spriteonly = linetoscr_16_shrink2f_aga_spronly;
1797 					break;
1798 					case 4:
1799 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink2f_aga_genlock : linetoscr_32_shrink2f_aga;
1800 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink2f_aga_spr_genlock : linetoscr_32_shrink2f_aga_spr;
1801 					pfield_do_linetoscr_spriteonly = linetoscr_32_shrink2f_aga_spronly;
1802 					break;
1803 				}
1804 			} else {
1805 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1806 					case 2:
1807 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink2_aga_genlock : linetoscr_16_shrink2_aga;
1808 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink2_aga_spr_genlock : linetoscr_16_shrink2_aga_spr;
1809 					pfield_do_linetoscr_spriteonly = linetoscr_16_shrink2_aga_spronly;
1810 					break;
1811 					case 4:
1812 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink2_aga_genlock : linetoscr_32_shrink2_aga;
1813 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink2_aga_spr_genlock : linetoscr_32_shrink2_aga_spr;
1814 					pfield_do_linetoscr_spriteonly = linetoscr_32_shrink2_aga_spronly;
1815 					break;
1816 				}
1817 			}
1818 		}
1819 		if (get_shdelay_add()) {
1820 			pfield_do_linetoscr_shdelay_normal = pfield_do_linetoscr_normal;
1821 			pfield_do_linetoscr_shdelay_sprite = pfield_do_linetoscr_sprite;
1822 			pfield_do_linetoscr_normal = pfield_do_linetoscr_normal_shdelay;
1823 			pfield_do_linetoscr_sprite = pfield_do_linetoscr_sprite_shdelay;
1824 		}
1825 	}
1826 #endif
1827 #ifdef ECS_DENISE
1828 	if (!(currprefs.chipset_mask & CSMASK_AGA) && ecsshres) {
1829 		// TODO: genlock support
1830 		if (res_shift == 0) {
1831 			switch (gfxvidinfo.drawbuffer.pixbytes) {
1832 				case 2:
1833 				pfield_do_linetoscr_normal = linetoscr_16_sh;
1834 				pfield_do_linetoscr_sprite = linetoscr_16_sh_spr;
1835 				break;
1836 				case 4:
1837 				pfield_do_linetoscr_normal = linetoscr_32_sh;
1838 				pfield_do_linetoscr_sprite = linetoscr_32_sh_spr;
1839 				break;
1840 			}
1841 		} else if (res_shift == -1) {
1842 			if (currprefs.gfx_lores_mode) {
1843 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1844 					case 2:
1845 					pfield_do_linetoscr_normal = linetoscr_16_shrink1f_sh;
1846 					pfield_do_linetoscr_sprite = linetoscr_16_shrink1f_sh_spr;
1847 					break;
1848 					case 4:
1849 					pfield_do_linetoscr_normal = linetoscr_32_shrink1f_sh;
1850 					pfield_do_linetoscr_sprite = linetoscr_32_shrink1f_sh_spr;
1851 					break;
1852 				}
1853 			} else {
1854 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1855 					case 2:
1856 					pfield_do_linetoscr_normal = linetoscr_16_shrink1_sh;
1857 					pfield_do_linetoscr_sprite = linetoscr_16_shrink1_sh_spr;
1858 					break;
1859 					case 4:
1860 					pfield_do_linetoscr_normal = linetoscr_32_shrink1_sh;
1861 					pfield_do_linetoscr_sprite = linetoscr_32_shrink1_sh_spr;
1862 					break;
1863 				}
1864 			}
1865 		} else if (res_shift == -2) {
1866 			if (currprefs.gfx_lores_mode) {
1867 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1868 					case 2:
1869 					pfield_do_linetoscr_normal = linetoscr_16_shrink2f_sh;
1870 					pfield_do_linetoscr_sprite = linetoscr_16_shrink2f_sh_spr;
1871 					break;
1872 					case 4:
1873 					pfield_do_linetoscr_normal = linetoscr_32_shrink2f_sh;
1874 					pfield_do_linetoscr_sprite = linetoscr_32_shrink2f_sh_spr;
1875 					break;
1876 				}
1877 			} else {
1878 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1879 					case 2:
1880 					pfield_do_linetoscr_normal = linetoscr_16_shrink2_sh;
1881 					pfield_do_linetoscr_sprite = linetoscr_16_shrink2_sh_spr;
1882 					break;
1883 					case 4:
1884 					pfield_do_linetoscr_normal = linetoscr_32_shrink2_sh;
1885 					pfield_do_linetoscr_sprite = linetoscr_32_shrink2_sh_spr;
1886 					break;
1887 				}
1888 			}
1889 		}
1890 	}
1891 #endif
1892 	if (!(currprefs.chipset_mask & CSMASK_AGA) && !ecsshres) {
1893 		if (res_shift == 0) {
1894 			switch (gfxvidinfo.drawbuffer.pixbytes) {
1895 				case 2:
1896 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_genlock : linetoscr_16;
1897 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_spr_genlock : linetoscr_16_spr;
1898 				break;
1899 				case 4:
1900 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_genlock : linetoscr_32;
1901 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_spr_genlock : linetoscr_32_spr;
1902 				break;
1903 			}
1904 		} else if (res_shift == 2) {
1905 			switch (gfxvidinfo.drawbuffer.pixbytes) {
1906 				case 2:
1907 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch2_genlock : linetoscr_16_stretch2;
1908 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch2_spr_genlock : linetoscr_16_stretch2_spr;
1909 				break;
1910 				case 4:
1911 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_stretch2_genlock : linetoscr_32_stretch2;
1912 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_stretch2_spr_genlock : linetoscr_32_stretch2_spr;
1913 				break;
1914 			}
1915 		} else if (res_shift == 1) {
1916 			switch (gfxvidinfo.drawbuffer.pixbytes) {
1917 				case 2:
1918 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_stretch1_genlock : linetoscr_16_stretch1;
1919 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_stretch1_spr_genlock : linetoscr_16_stretch1_spr;
1920 				break;
1921 				case 4:
1922 				pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_stretch1_genlock : linetoscr_32_stretch1;
1923 				pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_stretch1_spr_genlock : linetoscr_32_stretch1_spr;
1924 				break;
1925 			}
1926 		} else if (res_shift == -1) {
1927 				if (currprefs.gfx_lores_mode) {
1928 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1929 					case 2:
1930 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink1f_genlock : linetoscr_16_shrink1f;
1931 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink1f_spr_genlock : linetoscr_16_shrink1f_spr;
1932 					break;
1933 					case 4:
1934 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink1f_genlock : linetoscr_32_shrink1f;
1935 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink1f_spr_genlock : linetoscr_32_shrink1f_spr;
1936 					break;
1937 				}
1938 			} else {
1939 				switch (gfxvidinfo.drawbuffer.pixbytes) {
1940 					case 2:
1941 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_16_shrink1_genlock : linetoscr_16_shrink1;
1942 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_16_shrink1_spr_genlock : linetoscr_16_shrink1_spr;
1943 					break;
1944 					case 4:
1945 					pfield_do_linetoscr_normal = need_genlock_data ? linetoscr_32_shrink1_genlock : linetoscr_32_shrink1;
1946 					pfield_do_linetoscr_sprite = need_genlock_data ? linetoscr_32_shrink1_spr_genlock : linetoscr_32_shrink1_spr;
1947 					break;
1948 				}
1949 			}
1950 		}
1951 	}
1952 }
1953 
1954 // left or right AGA border sprite
pfield_do_linetoscr_bordersprite_aga(int start,int stop,bool blank)1955 static void pfield_do_linetoscr_bordersprite_aga (int start, int stop, bool blank)
1956 {
1957 	if (blank) {
1958 		pfield_do_fill_line (start, stop, blank);
1959 		return;
1960 	}
1961 	pfield_do_linetoscr_spriteonly(src_pixel, start, stop);
1962 }
1963 
dummy_worker(int start,int stop,bool blank)1964 static void dummy_worker (int start, int stop, bool blank)
1965 {
1966 }
1967 
1968 static int ham_decode_pixel;
1969 static unsigned int ham_lastcolor;
1970 
1971 /* Decode HAM in the invisible portion of the display (left of VISIBLE_LEFT_BORDER),
1972  * but don't draw anything in.  This is done to prepare HAM_LASTCOLOR for later,
1973  * when decode_ham runs.
1974  *
1975  */
init_ham_decoding(void)1976 static void init_ham_decoding (void)
1977 {
1978 	int unpainted_amiga = unpainted;
1979 
1980 	ham_decode_pixel = src_pixel;
1981 	ham_lastcolor = color_reg_get (&colors_for_drawing, 0);
1982 
1983 	if (!bplham) {
1984 		if (unpainted_amiga > 0) {
1985 			int pv = pixdata.apixels[ham_decode_pixel + unpainted_amiga - 1];
1986 #ifdef AGA
1987 			if (currprefs.chipset_mask & CSMASK_AGA)
1988 				ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor] & 0xffffff;
1989 			else
1990 #endif
1991 				ham_lastcolor = colors_for_drawing.color_regs_ecs[pv] & 0xfff;
1992 		}
1993 #ifdef AGA
1994 	} else if (currprefs.chipset_mask & CSMASK_AGA) {
1995 		if (bplplanecnt >= 7) { /* AGA mode HAM8 */
1996 			while (unpainted_amiga-- > 0) {
1997 				int pv = pixdata.apixels[ham_decode_pixel++] ^ bplxor;
1998 				switch (pv & 0x3)
1999 				{
2000 				case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2] & 0xffffff; break;
2001 				case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break;
2002 				case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break;
2003 				case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break;
2004 				}
2005 			}
2006 		} else { /* AGA mode HAM6 */
2007 			while (unpainted_amiga-- > 0) {
2008 				int pw = pixdata.apixels[ham_decode_pixel++];
2009 				int pv = pw ^ bplxor;
2010 				uae_u32 pc = ((pw & 0xf) << 0) | ((pw & 0xf) << 4);
2011 				switch (pv & 0x30)
2012 				{
2013 				case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv & 0x0f] & 0xffffff; break;
2014 				case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= pc << 0; break;
2015 				case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= pc << 16; break;
2016 				case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= pc << 8; break;
2017 				}
2018 			}
2019 		}
2020 #endif
2021 	} else {
2022 		/* OCS/ECS mode HAM6 */
2023 		while (unpainted_amiga-- > 0) {
2024 			int pv = pixdata.apixels[ham_decode_pixel++];
2025 			switch (pv & 0x30)
2026 			{
2027 			case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv] & 0xfff; break;
2028 			case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break;
2029 			case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break;
2030 			case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break;
2031 			}
2032 		}
2033 	}
2034 }
2035 
decode_ham(int pix,int stoppos,bool blank)2036 static void decode_ham (int pix, int stoppos, bool blank)
2037 {
2038 	int todraw_amiga = res_shift_from_window (stoppos - pix);
2039 
2040 	if (!bplham) {
2041 		while (todraw_amiga-- > 0) {
2042 			int pv = pixdata.apixels[ham_decode_pixel];
2043 #ifdef AGA
2044 			if (currprefs.chipset_mask & CSMASK_AGA)
2045 				ham_lastcolor = colors_for_drawing.color_regs_aga[pv ^ bplxor] & 0xffffff;
2046 			else
2047 #endif
2048 				ham_lastcolor = colors_for_drawing.color_regs_ecs[pv] & 0xfff;
2049 
2050 			ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
2051 		}
2052 #ifdef AGA
2053 	} else if (currprefs.chipset_mask & CSMASK_AGA) {
2054 		if (bplplanecnt >= 7) { /* AGA mode HAM8 */
2055 			while (todraw_amiga-- > 0) {
2056 				int pv = pixdata.apixels[ham_decode_pixel] ^ bplxor;
2057 				switch (pv & 0x3)
2058 				{
2059 				case 0x0: ham_lastcolor = colors_for_drawing.color_regs_aga[pv >> 2] & 0xffffff; break;
2060 				case 0x1: ham_lastcolor &= 0xFFFF03; ham_lastcolor |= (pv & 0xFC); break;
2061 				case 0x2: ham_lastcolor &= 0x03FFFF; ham_lastcolor |= (pv & 0xFC) << 16; break;
2062 				case 0x3: ham_lastcolor &= 0xFF03FF; ham_lastcolor |= (pv & 0xFC) << 8; break;
2063 				}
2064 				ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
2065 			}
2066 		} else { /* AGA mode HAM6 */
2067 			while (todraw_amiga-- > 0) {
2068 				int pw = pixdata.apixels[ham_decode_pixel];
2069 				int pv = pw ^ bplxor;
2070 				uae_u32 pc = ((pw & 0xf) << 0) | ((pw & 0xf) << 4);
2071 				switch (pv & 0x30)
2072 				{
2073 				case 0x00: ham_lastcolor = colors_for_drawing.color_regs_aga[pv & 0x0f] & 0xffffff; break;
2074 				case 0x10: ham_lastcolor &= 0xFFFF00; ham_lastcolor |= pc << 0; break;
2075 				case 0x20: ham_lastcolor &= 0x00FFFF; ham_lastcolor |= pc << 16; break;
2076 				case 0x30: ham_lastcolor &= 0xFF00FF; ham_lastcolor |= pc << 8; break;
2077 				}
2078 				ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
2079 			}
2080 		}
2081 #endif
2082 	} else {
2083 		/* OCS/ECS mode HAM6 */
2084 		while (todraw_amiga-- > 0) {
2085 			int pv = pixdata.apixels[ham_decode_pixel];
2086 			switch (pv & 0x30)
2087 			{
2088 			case 0x00: ham_lastcolor = colors_for_drawing.color_regs_ecs[pv] & 0xfff; break;
2089 			case 0x10: ham_lastcolor &= 0xFF0; ham_lastcolor |= (pv & 0xF); break;
2090 			case 0x20: ham_lastcolor &= 0x0FF; ham_lastcolor |= (pv & 0xF) << 8; break;
2091 			case 0x30: ham_lastcolor &= 0xF0F; ham_lastcolor |= (pv & 0xF) << 4; break;
2092 			}
2093 			ham_linebuf[ham_decode_pixel++] = ham_lastcolor;
2094 		}
2095 	}
2096 }
2097 
erase_ham_right_border(int pix,int stoppos,bool blank)2098 static void erase_ham_right_border(int pix, int stoppos, bool blank)
2099 {
2100 	if (stoppos < playfield_end)
2101 		return;
2102 	// erase right border in HAM modes or old HAM data may be visible
2103 	// if DDFSTOP < DIWSTOP (Uridium II title screen)
2104 	int todraw_amiga = res_shift_from_window (stoppos - pix);
2105 	while (todraw_amiga-- > 0)
2106 		ham_linebuf[ham_decode_pixel++] = 0;
2107 }
2108 
gen_pfield_tables(void)2109 static void gen_pfield_tables (void)
2110 {
2111 	int i;
2112 
2113 	for (i = 0; i < 256; i++) {
2114 		int plane1 = ((i >> 0) & 1) | ((i >> 1) & 2) | ((i >> 2) & 4) | ((i >> 3) & 8);
2115 		int plane2 = ((i >> 1) & 1) | ((i >> 2) & 2) | ((i >> 3) & 4) | ((i >> 4) & 8);
2116 
2117 		dblpf_2nd1[i] = plane1 == 0 && plane2 != 0;
2118 		dblpf_2nd2[i] = plane2 != 0;
2119 
2120 #ifdef AGA
2121 		dblpf_ind1_aga[i] = plane1 == 0 ? plane2 : plane1;
2122 		dblpf_ind2_aga[i] = plane2 == 0 ? plane1 : plane2;
2123 #endif
2124 
2125 		dblpf_ms1[i] = plane1 == 0 ? (plane2 == 0 ? 16 : 8) : 0;
2126 		dblpf_ms2[i] = plane2 == 0 ? (plane1 == 0 ? 16 : 0) : 8;
2127 		dblpf_ms[i] = i == 0 ? 16 : 8;
2128 
2129 		if (plane2 > 0)
2130 			plane2 += 8;
2131 		dblpf_ind1[i] = i >= 128 ? i & 0x7F : (plane1 == 0 ? plane2 : plane1);
2132 		dblpf_ind2[i] = i >= 128 ? i & 0x7F : (plane2 == 0 ? plane1 : plane2);
2133 
2134 		// Hack for OCS/ECS-only dualplayfield chipset bug.
2135 		// If PF2P2 is invalid (>5), playfield color becomes transparent but
2136 		// playfield still hides playfield under it! (if plfpri is set)
2137 		if (i & 64) {
2138 			dblpf_ind2[i] = 0;
2139 			dblpf_ind1[i] = 0;
2140 		}
2141 
2142 		sprite_offs[i] = (i & 15) ? 0 : 2;
2143 
2144 		clxtab[i] = ((((i & 3) && (i & 12)) << 9)
2145 			| (((i & 3) && (i & 48)) << 10)
2146 			| (((i & 3) && (i & 192)) << 11)
2147 			| (((i & 12) && (i & 48)) << 12)
2148 			| (((i & 12) && (i & 192)) << 13)
2149 			| (((i & 48) && (i & 192)) << 14));
2150 
2151 	}
2152 
2153 	memset (all_ones, 0xff, MAX_PIXELS_PER_LINE);
2154 
2155 }
2156 
2157 /* When looking at this function and the ones that inline it, bear in mind
2158 what an optimizing compiler will do with this code.  All callers of this
2159 function only pass in constant arguments (except for E).  This means
2160 that many of the if statements will go away completely after inlining.  */
draw_sprites_1(struct sprite_entry * e,int dualpf,int has_attach)2161 STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int dualpf, int has_attach)
2162 {
2163 	uae_u16 *buf = spixels + e->first_pixel;
2164 	uae_u8 *stbuf = spixstate.bytes + e->first_pixel;
2165 	int spr_pos, pos;
2166 
2167 	buf -= e->pos;
2168 	stbuf -= e->pos;
2169 
2170 	spr_pos = e->pos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << sprite_buffer_res);
2171 
2172 	if (spr_pos < sprite_first_x)
2173 		sprite_first_x = spr_pos;
2174 
2175 	for (pos = e->pos; pos < e->max; pos++, spr_pos++) {
2176 		if (spr_pos >= 0 && spr_pos < MAX_PIXELS_PER_LINE) {
2177 			spritepixels[spr_pos].data = buf[pos];
2178 			spritepixels[spr_pos].stdata = stbuf[pos];
2179 			spritepixels[spr_pos].attach = has_attach;
2180 		}
2181 	}
2182 
2183 	if (spr_pos > sprite_last_x)
2184 		sprite_last_x = spr_pos;
2185 }
2186 
2187 /* See comments above.  Do not touch if you don't know what's going on.
2188 * (We do _not_ want the following to be inlined themselves).  */
2189 /* lores bitplane, lores sprites */
draw_sprites_normal_sp_nat(struct sprite_entry * e)2190 static void NOINLINE draw_sprites_normal_sp_nat (struct sprite_entry *e) { draw_sprites_1 (e, 0, 0); }
draw_sprites_normal_dp_nat(struct sprite_entry * e)2191 static void NOINLINE draw_sprites_normal_dp_nat (struct sprite_entry *e) { draw_sprites_1 (e, 1, 0); }
draw_sprites_normal_sp_at(struct sprite_entry * e)2192 static void NOINLINE draw_sprites_normal_sp_at (struct sprite_entry *e) { draw_sprites_1 (e, 0, 1); }
draw_sprites_normal_dp_at(struct sprite_entry * e)2193 static void NOINLINE draw_sprites_normal_dp_at (struct sprite_entry *e) { draw_sprites_1 (e, 1, 1); }
2194 
2195 #ifdef AGA
2196 /* not very optimized */
draw_sprites_aga(struct sprite_entry * e,int aga)2197 STATIC_INLINE void draw_sprites_aga (struct sprite_entry *e, int aga)
2198 {
2199 	draw_sprites_1 (e, bpldualpf, e->has_attached);
2200 }
2201 #endif
2202 
draw_sprites_ecs(struct sprite_entry * e)2203 STATIC_INLINE void draw_sprites_ecs (struct sprite_entry *e)
2204 {
2205 	if (e->has_attached) {
2206 		if (bpldualpf)
2207 			draw_sprites_normal_dp_at (e);
2208 		else
2209 			draw_sprites_normal_sp_at (e);
2210 	} else {
2211 		if (bpldualpf)
2212 			draw_sprites_normal_dp_nat (e);
2213 		else
2214 			draw_sprites_normal_sp_nat (e);
2215 	}
2216 }
2217 
2218 #ifdef AGA
2219 /* clear possible bitplane data outside DIW area */
clear_bitplane_border_aga(void)2220 static void clear_bitplane_border_aga (void)
2221 {
2222 	int len, shift = res_shift;
2223 	uae_u8 v = 0;
2224 
2225 	if (shift < 0) {
2226 		shift = -shift;
2227 		len = (real_playfield_start - playfield_start) << shift;
2228 		memset (pixdata.apixels + pixels_offset + (playfield_start << shift), v, len);
2229 		len = (playfield_end - real_playfield_end) << shift;
2230 		memset (pixdata.apixels + pixels_offset + (real_playfield_end << shift), v, len);
2231 	} else {
2232 		len = (real_playfield_start - playfield_start) >> shift;
2233 		memset (pixdata.apixels + pixels_offset + (playfield_start >> shift), v, len);
2234 		len = (playfield_end - real_playfield_end) >> shift;
2235 		memset (pixdata.apixels + pixels_offset + (real_playfield_end >> shift), v, len);
2236 	}
2237 }
2238 #endif
2239 
weird_bitplane_fix(int start,int end)2240 static void weird_bitplane_fix (int start, int end)
2241 {
2242 	int sh = lores_shift;
2243 	uae_u8 *p = pixdata.apixels + pixels_offset;
2244 
2245 	start >>= sh;
2246 	end >>= sh;
2247 	if (bplplanecnt == 5 && !bpldualpf) {
2248 		/* emulate OCS/ECS only undocumented "SWIV" hardware feature */
2249 		for (int i = start; i < end; i++) {
2250 			if (p[i] & 16)
2251 				p[i] = 16;
2252 		}
2253 	} else if (bpldualpf && bpldualpfpri) {
2254 		/* in dualplayfield mode this feature is even more strange.. */
2255 		for (int i = start; i < end; i++) {
2256 			if (p[i] & (2 | 8 | 32))
2257 				p[i] |= 0x40;
2258 		}
2259 	} else if (bpldualpf && !bpldualpfpri) {
2260 		for (int i = start; i < end; i++) {
2261 			p[i] &= ~(2 | 8 | 32);
2262 		}
2263 	}
2264 }
2265 
2266 /* We use the compiler's inlining ability to ensure that PLANES is in effect a compile time
2267 constant.  That will cause some unnecessary code to be optimized away.
2268 Don't touch this if you don't know what you are doing.  */
2269 
2270 #define MERGE(a,b,mask,shift) do {\
2271 	uae_u32 tmp = mask & (a ^ (b >> shift)); \
2272 	a ^= tmp; \
2273 	b ^= (tmp << shift); \
2274 } while (0)
2275 
2276 #define GETLONG(P) (*(uae_u32 *)P)
2277 
pfield_doline_1(uae_u32 * pixels,int wordcount,int planes)2278 STATIC_INLINE void pfield_doline_1 (uae_u32 *pixels, int wordcount, int planes)
2279 {
2280 	while (wordcount-- > 0) {
2281 		uae_u32 b0, b1, b2, b3, b4, b5, b6, b7;
2282 
2283 		b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0;
2284 		switch (planes) {
2285 #ifdef AGA
2286 		case 8: b0 = GETLONG (real_bplpt[7]); real_bplpt[7] += 4;
2287 		case 7: b1 = GETLONG (real_bplpt[6]); real_bplpt[6] += 4;
2288 #endif
2289 		case 6: b2 = GETLONG (real_bplpt[5]); real_bplpt[5] += 4;
2290 		case 5: b3 = GETLONG (real_bplpt[4]); real_bplpt[4] += 4;
2291 		case 4: b4 = GETLONG (real_bplpt[3]); real_bplpt[3] += 4;
2292 		case 3: b5 = GETLONG (real_bplpt[2]); real_bplpt[2] += 4;
2293 		case 2: b6 = GETLONG (real_bplpt[1]); real_bplpt[1] += 4;
2294 		case 1: b7 = GETLONG (real_bplpt[0]); real_bplpt[0] += 4;
2295 		}
2296 
2297 		MERGE (b0, b1, 0x55555555, 1);
2298 		MERGE (b2, b3, 0x55555555, 1);
2299 		MERGE (b4, b5, 0x55555555, 1);
2300 		MERGE (b6, b7, 0x55555555, 1);
2301 
2302 		MERGE (b0, b2, 0x33333333, 2);
2303 		MERGE (b1, b3, 0x33333333, 2);
2304 		MERGE (b4, b6, 0x33333333, 2);
2305 		MERGE (b5, b7, 0x33333333, 2);
2306 
2307 		MERGE (b0, b4, 0x0f0f0f0f, 4);
2308 		MERGE (b1, b5, 0x0f0f0f0f, 4);
2309 		MERGE (b2, b6, 0x0f0f0f0f, 4);
2310 		MERGE (b3, b7, 0x0f0f0f0f, 4);
2311 
2312 		MERGE (b0, b1, 0x00ff00ff, 8);
2313 		MERGE (b2, b3, 0x00ff00ff, 8);
2314 		MERGE (b4, b5, 0x00ff00ff, 8);
2315 		MERGE (b6, b7, 0x00ff00ff, 8);
2316 
2317 		MERGE (b0, b2, 0x0000ffff, 16);
2318 		do_put_mem_long (pixels, b0);
2319 		do_put_mem_long (pixels + 4, b2);
2320 		MERGE (b1, b3, 0x0000ffff, 16);
2321 		do_put_mem_long (pixels + 2, b1);
2322 		do_put_mem_long (pixels + 6, b3);
2323 		MERGE (b4, b6, 0x0000ffff, 16);
2324 		do_put_mem_long (pixels + 1, b4);
2325 		do_put_mem_long (pixels + 5, b6);
2326 		MERGE (b5, b7, 0x0000ffff, 16);
2327 		do_put_mem_long (pixels + 3, b5);
2328 		do_put_mem_long (pixels + 7, b7);
2329 		pixels += 8;
2330 	}
2331 }
2332 
2333 /* See above for comments on inlining.  These functions should _not_
2334 be inlined themselves.  */
pfield_doline_n1(uae_u32 * data,int count)2335 static void NOINLINE pfield_doline_n1 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 1); }
pfield_doline_n2(uae_u32 * data,int count)2336 static void NOINLINE pfield_doline_n2 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 2); }
pfield_doline_n3(uae_u32 * data,int count)2337 static void NOINLINE pfield_doline_n3 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 3); }
pfield_doline_n4(uae_u32 * data,int count)2338 static void NOINLINE pfield_doline_n4 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 4); }
pfield_doline_n5(uae_u32 * data,int count)2339 static void NOINLINE pfield_doline_n5 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 5); }
pfield_doline_n6(uae_u32 * data,int count)2340 static void NOINLINE pfield_doline_n6 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 6); }
2341 #ifdef AGA
pfield_doline_n7(uae_u32 * data,int count)2342 static void NOINLINE pfield_doline_n7 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 7); }
pfield_doline_n8(uae_u32 * data,int count)2343 static void NOINLINE pfield_doline_n8 (uae_u32 *data, int count) { pfield_doline_1 (data, count, 8); }
2344 #endif
2345 
pfield_doline(int lineno)2346 static void pfield_doline (int lineno)
2347 {
2348 	int wordcount = dp_for_drawing->plflinelen;
2349 	uae_u32 *data = pixdata.apixels_l + MAX_PIXELS_PER_LINE / 4;
2350 
2351 #ifdef SMART_UPDATE
2352 #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))
2353 	real_bplpt[0] = DATA_POINTER (0);
2354 	real_bplpt[1] = DATA_POINTER (1);
2355 	real_bplpt[2] = DATA_POINTER (2);
2356 	real_bplpt[3] = DATA_POINTER (3);
2357 	real_bplpt[4] = DATA_POINTER (4);
2358 	real_bplpt[5] = DATA_POINTER (5);
2359 #ifdef AGA
2360 	real_bplpt[6] = DATA_POINTER (6);
2361 	real_bplpt[7] = DATA_POINTER (7);
2362 #endif
2363 #endif
2364 
2365 	switch (bplplanecnt) {
2366 	default: break;
2367 	case 0: memset (data, 0, wordcount * 32); break;
2368 	case 1: pfield_doline_n1 (data, wordcount); break;
2369 	case 2: pfield_doline_n2 (data, wordcount); break;
2370 	case 3: pfield_doline_n3 (data, wordcount); break;
2371 	case 4: pfield_doline_n4 (data, wordcount); break;
2372 	case 5: pfield_doline_n5 (data, wordcount); break;
2373 	case 6: pfield_doline_n6 (data, wordcount); break;
2374 #ifdef AGA
2375 	case 7: pfield_doline_n7 (data, wordcount); break;
2376 	case 8: pfield_doline_n8 (data, wordcount); break;
2377 #endif
2378 	}
2379 
2380 	if (refresh_indicator_buffer && refresh_indicator_height > lineno) {
2381 		uae_u8 *opline = refresh_indicator_buffer + lineno * MAX_PIXELS_PER_LINE * 2;
2382 		wordcount *= 32;
2383 		if (!memcmp(opline, data, wordcount)) {
2384 			if (refresh_indicator_changed[lineno] != 0xff) {
2385 				refresh_indicator_changed[lineno]++;
2386 				if (refresh_indicator_changed[lineno] > refresh_indicator_changed_prev[lineno]) {
2387 					refresh_indicator_changed_prev[lineno] = refresh_indicator_changed[lineno];
2388 				}
2389 			}
2390 		} else {
2391 			memcpy(opline, data, wordcount);
2392 			if (refresh_indicator_changed[lineno] != refresh_indicator_changed_prev[lineno])
2393 				refresh_indicator_changed_prev[lineno] = 0;
2394 			refresh_indicator_changed[lineno] = 0;
2395 		}
2396 	}
2397 
2398 
2399 }
2400 
init_row_map(void)2401 void init_row_map (void)
2402 {
2403 	static uae_u8 *oldbufmem;
2404 	static int oldheight, oldpitch;
2405 	static bool oldgenlock;
2406 	int i, j;
2407 
2408 	if (gfxvidinfo.drawbuffer.height_allocated > max_uae_height) {
2409 		write_log (_T("Resolution too high, aborting\n"));
2410 		abort ();
2411 	}
2412 	if (!row_map) {
2413 		row_map = xmalloc(uae_u8*, max_uae_height + 1);
2414 		row_map_genlock = xmalloc(uae_u8*, max_uae_height + 1);
2415 	}
2416 
2417 	if (oldbufmem && oldbufmem == gfxvidinfo.drawbuffer.bufmem &&
2418 		oldheight == gfxvidinfo.drawbuffer.height_allocated &&
2419 		oldpitch == gfxvidinfo.drawbuffer.rowbytes &&
2420 		oldgenlock == init_genlock_data)
2421 		return;
2422 	xfree(row_map_genlock_buffer);
2423 	row_map_genlock_buffer = NULL;
2424 	if (init_genlock_data) {
2425 		row_map_genlock_buffer = xcalloc(uae_u8, gfxvidinfo.drawbuffer.width_allocated * (gfxvidinfo.drawbuffer.height_allocated + 2));
2426 	}
2427 	j = oldheight == 0 ? max_uae_height : oldheight;
2428 	for (i = gfxvidinfo.drawbuffer.height_allocated; i < max_uae_height + 1 && i < j + 1; i++) {
2429 		row_map[i] = row_tmp;
2430 		row_map_genlock[i] = row_tmp;
2431 	}
2432 	for (i = 0, j = 0; i < gfxvidinfo.drawbuffer.height_allocated; i++, j += gfxvidinfo.drawbuffer.rowbytes) {
2433 		row_map[i] = gfxvidinfo.drawbuffer.bufmem + j;
2434 		if (init_genlock_data) {
2435 			row_map_genlock[i] = row_map_genlock_buffer + gfxvidinfo.drawbuffer.width_allocated * (i + 1);
2436 		} else {
2437 			row_map_genlock[i] = NULL;
2438 		}
2439 	}
2440 	oldbufmem = gfxvidinfo.drawbuffer.bufmem;
2441 	oldheight = gfxvidinfo.drawbuffer.height_allocated;
2442 	oldpitch = gfxvidinfo.drawbuffer.rowbytes;
2443 	oldgenlock = init_genlock_data;
2444 }
2445 
init_aspect_maps(void)2446 static void init_aspect_maps (void)
2447 {
2448 	int i, maxl, h;
2449 
2450 	h = gfxvidinfo.drawbuffer.height_allocated;
2451 
2452 	if (h == 0)
2453 		/* Do nothing if the gfx driver hasn't initialized the screen yet */
2454 		return;
2455 
2456 	linedbld = linedbl = currprefs.gfx_vresolution;
2457 	if (doublescan > 0 && interlace_seen <= 0) {
2458 		linedbl = 0;
2459 		linedbld = 1;
2460 	}
2461 
2462 	if (native2amiga_line_map)
2463 		xfree (native2amiga_line_map);
2464 	if (amiga2aspect_line_map)
2465 		xfree (amiga2aspect_line_map);
2466 
2467 	/* At least for this array the +1 is necessary. */
2468 	amiga2aspect_line_map = xmalloc (int, (MAXVPOS + 1) * 2 + 1);
2469 	native2amiga_line_map = xmalloc (int, h);
2470 
2471 	maxl = (MAXVPOS + 1) << linedbld;
2472 	min_ypos_for_screen = minfirstline << linedbl;
2473 	max_drawn_amiga_line = -1;
2474 	for (i = 0; i < maxl; i++) {
2475 		int v = i - min_ypos_for_screen;
2476 		if (v >= h && max_drawn_amiga_line < 0)
2477 			max_drawn_amiga_line = v;
2478 		if (i < min_ypos_for_screen || v >= h)
2479 			v = -1;
2480 		amiga2aspect_line_map[i] = v;
2481 	}
2482 	if (max_drawn_amiga_line < 0)
2483 		max_drawn_amiga_line = maxl - min_ypos_for_screen;
2484 
2485 	for (i = 0; i < h; i++)
2486 		native2amiga_line_map[i] = -1;
2487 
2488 	for (i = maxl - 1; i >= min_ypos_for_screen; i--) {
2489 		int j;
2490 		if (amiga2aspect_line_map[i] == -1)
2491 			continue;
2492 		for (j = amiga2aspect_line_map[i]; j < h && native2amiga_line_map[j] == -1; j++)
2493 			native2amiga_line_map[j] = i >> linedbl;
2494 	}
2495 
2496 	gfxvidinfo.xchange = 1 << (RES_MAX - currprefs.gfx_resolution);
2497 	gfxvidinfo.ychange = linedbl ? 1 : 2;
2498 
2499 	visible_left_start = 0;
2500 	visible_right_stop = MAX_STOP;
2501 	visible_top_start = 0;
2502 	visible_bottom_stop = MAX_STOP;
2503 	set_blanking_limits ();
2504 }
2505 
2506 /*
2507 * A raster line has been built in the graphics buffer. Tell the graphics code
2508 * to do anything necessary to display it.
2509 */
do_flush_line_1(struct vidbuffer * vb,int lineno)2510 static void do_flush_line_1 (struct vidbuffer *vb, int lineno)
2511 {
2512 	if (lineno < first_drawn_line)
2513 		first_drawn_line = lineno;
2514 	if (lineno > last_drawn_line)
2515 		last_drawn_line = lineno;
2516 
2517 	if (gfxvidinfo.maxblocklines == 0) {
2518 		flush_line (vb, lineno);
2519 	} else {
2520 		if ((last_block_line + 2) < lineno) {
2521 			if (first_block_line != NO_BLOCK)
2522 				flush_block (vb, first_block_line, last_block_line);
2523 			first_block_line = lineno;
2524 		}
2525 		last_block_line = lineno;
2526 		if (last_block_line - first_block_line >= gfxvidinfo.maxblocklines) {
2527 			flush_block (vb, first_block_line, last_block_line);
2528 			first_block_line = last_block_line = NO_BLOCK;
2529 		}
2530 	}
2531 }
2532 
do_flush_line(struct vidbuffer * vb,int lineno)2533 STATIC_INLINE void do_flush_line (struct vidbuffer *vb, int lineno)
2534 {
2535 	if (vb)
2536 		do_flush_line_1 (vb, lineno);
2537 }
2538 
2539 /*
2540 * One drawing frame has been finished. Tell the graphics code about it.
2541 * Note that the actual flush_screen() call is a no-op for all reasonable
2542 * systems.
2543 */
2544 
do_flush_screen(struct vidbuffer * vb,int start,int stop)2545 static void do_flush_screen (struct vidbuffer *vb, int start, int stop)
2546 {
2547 	/* TODO: this flush operation is executed outside locked state!
2548 	Should be corrected.
2549 	(sjo 26.9.99) */
2550 
2551 	if (vb != gfxvidinfo.outbuffer)
2552 		return;
2553 
2554 	xlinecheck (start, stop);
2555 	if (gfxvidinfo.maxblocklines != 0 && first_block_line != NO_BLOCK) {
2556 		flush_block (vb, first_block_line, last_block_line);
2557 	}
2558 	unlockscr (vb);
2559 	if (start <= stop)
2560 		flush_screen (vb, start, stop);
2561 	else if (isvsync_chipset ())
2562 		flush_screen (vb, 0, 0); /* vsync mode */
2563 }
2564 
2565 /* We only save hardware registers during the hardware frame. Now, when
2566 * drawing the frame, we expand the data into a slightly more useful
2567 * form. */
pfield_expand_dp_bplcon(void)2568 static void pfield_expand_dp_bplcon (void)
2569 {
2570 	bool pfield_mode_changed = false;
2571 
2572 	bplres = dp_for_drawing->bplres;
2573 	bplplanecnt = dp_for_drawing->nr_planes;
2574 	bplham = dp_for_drawing->ham_seen;
2575 	bplehb = dp_for_drawing->ehb_seen;
2576 	if ((currprefs.chipset_mask & CSMASK_ECS_DENISE) && (dp_for_drawing->bplcon2 & 0x0200))
2577 		bplehb = 0;
2578 	issprites = dip_for_drawing->nr_sprites > 0;
2579 #ifdef ECS_DENISE
2580 	int oecsshres = ecsshres;
2581 	ecsshres = bplres == RES_SUPERHIRES && (currprefs.chipset_mask & CSMASK_ECS_DENISE) && !(currprefs.chipset_mask & CSMASK_AGA);
2582 	pfield_mode_changed = oecsshres != ecsshres;
2583 #endif
2584 
2585 	plf1pri = dp_for_drawing->bplcon2 & 7;
2586 	plf2pri = (dp_for_drawing->bplcon2 >> 3) & 7;
2587 	plf_sprite_mask = 0xFFFF0000 << (4 * plf2pri);
2588 	plf_sprite_mask |= (0x0000FFFF << (4 * plf1pri)) & 0xFFFF;
2589 	bpldualpf = (dp_for_drawing->bplcon0 & 0x400) == 0x400;
2590 	bpldualpfpri = (dp_for_drawing->bplcon2 & 0x40) == 0x40;
2591 
2592 #ifdef AGA
2593 	bpldualpf2of = (dp_for_drawing->bplcon3 >> 10) & 7;
2594 	sbasecol[0] = ((dp_for_drawing->bplcon4 >> 4) & 15) << 4;
2595 	sbasecol[1] = ((dp_for_drawing->bplcon4 >> 0) & 15) << 4;
2596 	bplxor = dp_for_drawing->bplcon4 >> 8;
2597 	int sh = (colors_for_drawing.extra >> CE_SHRES_DELAY) & 3;
2598 	if (sh != bpldelay_sh) {
2599 		bpldelay_sh = sh;
2600 		pfield_mode_changed = true;
2601 	}
2602 #endif
2603 	ecs_genlock_features_active = (currprefs.chipset_mask & CSMASK_ECS_DENISE) && ((dp_for_drawing->bplcon2 & 0x0c00) || ce_is_borderntrans(colors_for_drawing.extra)) ? 1 : 0;
2604 	if (ecs_genlock_features_active) {
2605 		ecs_genlock_features_colorkey = false;
2606 		ecs_genlock_features_mask = 0;
2607 		if (dp_for_drawing->bplcon3 & 0x0800) {
2608 			ecs_genlock_features_mask = 1 << ((dp_for_drawing->bplcon2 >> 12) & 7);
2609 		}
2610 		if (dp_for_drawing->bplcon3 & 0x0400) {
2611 			ecs_genlock_features_colorkey = true;
2612 		}
2613 	}
2614 	if (pfield_mode_changed)
2615 		pfield_set_linetoscr();
2616 }
2617 
isham(uae_u16 bplcon0)2618 static bool isham (uae_u16 bplcon0)
2619 {
2620 	int p = GET_PLANES (bplcon0);
2621 	if (!(bplcon0 & 0x800))
2622 		return 0;
2623 	if (currprefs.chipset_mask & CSMASK_AGA) {
2624 		// AGA only has 6 or 8 plane HAM
2625 		if (p == 6 || p == 8)
2626 			return 1;
2627 	} else {
2628 		// OCS/ECS also supports 5 plane HAM
2629 		if (GET_RES_DENISE (bplcon0) > 0)
2630 			return 0;
2631 		if (p >= 5)
2632 			return 1;
2633 	}
2634 	return 0;
2635 }
2636 
pfield_expand_dp_bplconx(int regno,int v)2637 static void pfield_expand_dp_bplconx (int regno, int v)
2638 {
2639 	if (regno == 0xffff) {
2640 		hposblank = 1;
2641 		return;
2642 	}
2643 	regno -= 0x1000;
2644 	switch (regno)
2645 	{
2646 	case 0x100: // BPLCON0
2647 		dp_for_drawing->bplcon0 = v;
2648 		dp_for_drawing->bplres = GET_RES_DENISE (v);
2649 		dp_for_drawing->nr_planes = GET_PLANES (v);
2650 		dp_for_drawing->ham_seen = isham (v);
2651 		break;
2652 	case 0x104: // BPLCON2
2653 		dp_for_drawing->bplcon2 = v;
2654 		break;
2655 #ifdef ECS_DENISE
2656 	case 0x106: // BPLCON3
2657 		dp_for_drawing->bplcon3 = v;
2658 		break;
2659 #endif
2660 #ifdef AGA
2661 	case 0x10c: // BPLCON4
2662 		dp_for_drawing->bplcon4 = v;
2663 		break;
2664 #endif
2665 	}
2666 	pfield_expand_dp_bplcon ();
2667 	set_res_shift(lores_shift - bplres);
2668 }
2669 
2670 static int drawing_color_matches;
2671 static enum { color_match_acolors, color_match_full } color_match_type;
2672 
2673 /* Set up colors_for_drawing to the state at the beginning of the currently drawn
2674 line.  Try to avoid copying color tables around whenever possible.  */
adjust_drawing_colors(int ctable,int need_full)2675 static void adjust_drawing_colors (int ctable, int need_full)
2676 {
2677 	if (drawing_color_matches != ctable || need_full < 0) {
2678 		if (need_full) {
2679 			color_reg_cpy (&colors_for_drawing, curr_color_tables + ctable);
2680 			color_match_type = color_match_full;
2681 		} else {
2682 			memcpy (colors_for_drawing.acolors, curr_color_tables[ctable].acolors,
2683 				sizeof colors_for_drawing.acolors);
2684 			colors_for_drawing.extra = curr_color_tables[ctable].extra;
2685 			color_match_type = color_match_acolors;
2686 		}
2687 		drawing_color_matches = ctable;
2688 	} else if (need_full && color_match_type != color_match_full) {
2689 		color_reg_cpy (&colors_for_drawing, &curr_color_tables[ctable]);
2690 		color_match_type = color_match_full;
2691 	}
2692 }
2693 
playfield_hard_way(line_draw_func worker_pfield,int first,int last)2694 static void playfield_hard_way(line_draw_func worker_pfield, int first, int last)
2695 {
2696 	if (first < real_playfield_start)  {
2697 		int next = last < real_playfield_start ? last : real_playfield_start;
2698 		int diff = next - first;
2699 		pfield_do_linetoscr_bordersprite_aga(first, next, false);
2700 		if (res_shift >= 0)
2701 			diff >>= res_shift;
2702 		else
2703 			diff <<= res_shift;
2704 		src_pixel += diff;
2705 		first = next;
2706 	}
2707 	(*worker_pfield)(first, last < real_playfield_end ? last : real_playfield_end, false);
2708 	if (last > real_playfield_end)
2709 		pfield_do_linetoscr_bordersprite_aga(real_playfield_end, last, false);
2710 }
2711 
do_color_changes(line_draw_func worker_border,line_draw_func worker_pfield,int vp)2712 static void do_color_changes (line_draw_func worker_border, line_draw_func worker_pfield, int vp)
2713 {
2714 	int i;
2715 	int lastpos = visible_left_border;
2716 	int endpos = visible_left_border + gfxvidinfo.drawbuffer.inwidth;
2717 
2718 	for (i = dip_for_drawing->first_color_change; i <= dip_for_drawing->last_color_change; i++) {
2719 		int regno = curr_color_changes[i].regno;
2720 		unsigned int value = curr_color_changes[i].value;
2721 		int nextpos, nextpos_in_range;
2722 
2723 		if (i == dip_for_drawing->last_color_change)
2724 			nextpos = endpos;
2725 		else
2726 			nextpos = coord_hw_to_window_x (curr_color_changes[i].linepos);
2727 
2728 		nextpos_in_range = nextpos;
2729 		if (nextpos > endpos)
2730 			nextpos_in_range = endpos;
2731 
2732 		// left hblank (left edge to hblank end)
2733 		if (nextpos_in_range > lastpos && lastpos < hblank_left_start) {
2734 			int t = nextpos_in_range <= hblank_left_start ? nextpos_in_range : hblank_left_start;
2735 			(*worker_border) (lastpos, t, true);
2736 			lastpos = t;
2737 		}
2738 
2739 		// left border (hblank end to playfield start)
2740 		if (nextpos_in_range > lastpos && lastpos < playfield_start) {
2741 			int t = nextpos_in_range <= playfield_start ? nextpos_in_range : playfield_start;
2742 			(*worker_border) (lastpos, t, false);
2743 			lastpos = t;
2744 		}
2745 
2746 		// playfield
2747 		if (nextpos_in_range > lastpos && lastpos >= playfield_start && lastpos < playfield_end) {
2748 			int t = nextpos_in_range <= playfield_end ? nextpos_in_range : playfield_end;
2749 			if (plf2pri > 5 && !(currprefs.chipset_mask & CSMASK_AGA))
2750 				weird_bitplane_fix (lastpos, t);
2751 			if (bplxor && may_require_hard_way && worker_pfield != pfield_do_linetoscr_bordersprite_aga)
2752 				playfield_hard_way(worker_pfield, lastpos, t);
2753 			else
2754 				(*worker_pfield) (lastpos, t, false);
2755 			lastpos = t;
2756 		}
2757 
2758 		// right border (playfield end to hblank start)
2759 		if (nextpos_in_range > lastpos && lastpos >= playfield_end) {
2760 			int t = nextpos_in_range <= hblank_right_stop ? nextpos_in_range : hblank_right_stop;
2761 			(*worker_border) (lastpos, t, false);
2762 			lastpos = t;
2763 		}
2764 
2765 		// right hblank (hblank start to right edge, hblank start may be earlier than playfield end)
2766 		if (nextpos_in_range > hblank_right_stop) {
2767 			(*worker_border) (hblank_right_stop, nextpos_in_range, true);
2768 			lastpos = nextpos_in_range;
2769 		}
2770 
2771 		if (regno >= 0x1000) {
2772 			pfield_expand_dp_bplconx (regno, value);
2773 		} else if (regno >= 0) {
2774 			if (regno == 0 && (value & COLOR_CHANGE_BRDBLANK)) {
2775 				colors_for_drawing.extra &= ~(1 << CE_BORDERBLANK);
2776 				colors_for_drawing.extra &= ~(1 << CE_BORDERNTRANS);
2777 				colors_for_drawing.extra &= ~(1 << CE_BORDERSPRITE);
2778 				colors_for_drawing.extra |= (value & 1) != 0 ? (1 << CE_BORDERBLANK) : 0;
2779 				colors_for_drawing.extra |= (value & 3) == 2 ? (1 << CE_BORDERSPRITE) : 0;
2780 				colors_for_drawing.extra |= (value & 5) == 4 ? (1 << CE_BORDERNTRANS) : 0;
2781 			} else if (regno == 0 && (value & COLOR_CHANGE_SHRES_DELAY)) {
2782 				colors_for_drawing.extra &= ~(1 << CE_SHRES_DELAY);
2783 				colors_for_drawing.extra &= ~(1 << (CE_SHRES_DELAY + 1));
2784 				colors_for_drawing.extra |= (value & 3) << CE_SHRES_DELAY;
2785 				pfield_expand_dp_bplcon();
2786 			} else {
2787 				color_reg_set (&colors_for_drawing, regno, value);
2788 				colors_for_drawing.acolors[regno] = getxcolor (value);
2789 			}
2790 		}
2791 		if (lastpos >= endpos)
2792 			break;
2793 	}
2794 #if 1
2795 	if (vp < visible_top_start || vp >= visible_bottom_stop) {
2796 		// outside of visible area
2797 		// Just overwrite with black. Above code needs to run because of custom registers,
2798 		// not worth the trouble for separate code path just for max 10 lines or so
2799 		(*worker_border) (visible_left_border, visible_left_border + gfxvidinfo.drawbuffer.inwidth, true);
2800 	}
2801 #endif
2802 }
2803 
is_color_changes(struct draw_info * di)2804 STATIC_INLINE bool is_color_changes(struct draw_info *di)
2805 {
2806 	int regno = curr_color_changes[di->first_color_change].regno;
2807 	int changes = di->nr_color_changes;
2808 	return changes > 1 || (changes == 1 && regno != 0xffff && regno != -1);
2809 }
2810 
2811 enum double_how {
2812 	dh_buf,
2813 	dh_line,
2814 	dh_emerg
2815 };
2816 
pfield_draw_line(struct vidbuffer * vb,int lineno,int gfx_ypos,int follow_ypos)2817 static void pfield_draw_line (struct vidbuffer *vb, int lineno, int gfx_ypos, int follow_ypos)
2818 {
2819 	static int warned = 0;
2820 	int border = 0;
2821 	int do_double = 0;
2822 	bool have_color_changes;
2823 	enum double_how dh;
2824 	int ls = linestate[lineno];
2825 
2826 	dp_for_drawing = line_decisions + lineno;
2827 	dip_for_drawing = curr_drawinfo + lineno;
2828 
2829 	if (dp_for_drawing->plfleft >= 0) {
2830 		lines_count++;
2831 		resolution_count[dp_for_drawing->bplres]++;
2832 	}
2833 
2834 	switch (ls)
2835 	{
2836 	case LINE_REMEMBERED_AS_PREVIOUS:
2837 //		if (!warned) // happens when program messes up with VPOSW
2838 //			write_log (_T("Shouldn't get here... this is a bug.\n")), warned++;
2839 		return;
2840 
2841 	case LINE_BLACK:
2842 		linestate[lineno] = LINE_REMEMBERED_AS_BLACK;
2843 		border = -1;
2844 		break;
2845 
2846 	case LINE_REMEMBERED_AS_BLACK:
2847 		return;
2848 
2849 	case LINE_AS_PREVIOUS:
2850 		dp_for_drawing--;
2851 		dip_for_drawing--;
2852 		linestate[lineno] = LINE_DONE_AS_PREVIOUS;
2853 		if (dp_for_drawing->plfleft < 0)
2854 			border = 1;
2855 		break;
2856 
2857 	case LINE_DONE_AS_PREVIOUS:
2858 		/* fall through */
2859 	case LINE_DONE:
2860 		return;
2861 
2862 	case LINE_DECIDED_DOUBLE:
2863 		if (follow_ypos >= 0) {
2864 			do_double = 1;
2865 			linestate[lineno + 1] = LINE_DONE_AS_PREVIOUS;
2866 		}
2867 
2868 		/* fall through */
2869 	default:
2870 		if (dp_for_drawing->plfleft < 0)
2871 			border = 1;
2872 		linestate[lineno] = LINE_DONE;
2873 		break;
2874 	}
2875 
2876 	have_color_changes = is_color_changes(dip_for_drawing);
2877 
2878 	dh = dh_line;
2879 	xlinebuffer = gfxvidinfo.drawbuffer.linemem;
2880 	if (xlinebuffer == 0 && do_double
2881 		&& (border == 0 || have_color_changes))
2882 		xlinebuffer = gfxvidinfo.drawbuffer.emergmem, dh = dh_emerg;
2883 	if (xlinebuffer == 0)
2884 		xlinebuffer = row_map[gfx_ypos], dh = dh_buf;
2885 	xlinebuffer -= linetoscr_x_adjust_pixbytes;
2886 	xlinebuffer_genlock = row_map_genlock[gfx_ypos] - linetoscr_x_adjust_pixels;
2887 
2888 	if (border == 0) {
2889 
2890 		pfield_expand_dp_bplcon ();
2891 		pfield_init_linetoscr (false);
2892 		pfield_doline (lineno);
2893 
2894 		adjust_drawing_colors (dp_for_drawing->ctable, dp_for_drawing->ham_seen || bplehb || ecsshres);
2895 
2896 		/* The problem is that we must call decode_ham() BEFORE we do the sprites. */
2897 		if (dp_for_drawing->ham_seen) {
2898 			int ohposblank = hposblank;
2899 			init_ham_decoding ();
2900 			do_color_changes (dummy_worker, decode_ham, lineno);
2901 			if (have_color_changes) {
2902 				// do_color_changes() did color changes, reset colors back to original state
2903 				adjust_drawing_colors (dp_for_drawing->ctable, -1);
2904 				pfield_expand_dp_bplcon ();
2905 			}
2906 			hposblank = ohposblank;
2907 			ham_decode_pixel = src_pixel;
2908 			bplham = dp_for_drawing->ham_at_start;
2909 		}
2910 
2911 		if (dip_for_drawing->nr_sprites) {
2912 			int i;
2913 #ifdef AGA
2914 			if (ce_is_bordersprite(colors_for_drawing.extra) && dp_for_drawing->bordersprite_seen && !ce_is_borderblank(colors_for_drawing.extra))
2915 				clear_bitplane_border_aga ();
2916 #endif
2917 
2918 			for (i = 0; i < dip_for_drawing->nr_sprites; i++) {
2919 #ifdef AGA
2920 				if (currprefs.chipset_mask & CSMASK_AGA)
2921 					draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i, 1);
2922 				else
2923 #endif
2924 					draw_sprites_ecs (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i);
2925 			}
2926 		}
2927 
2928 #ifdef AGA
2929 		if (dip_for_drawing->nr_sprites && ce_is_bordersprite(colors_for_drawing.extra) && !ce_is_borderblank(colors_for_drawing.extra) && dp_for_drawing->bordersprite_seen)
2930 			do_color_changes (pfield_do_linetoscr_bordersprite_aga, pfield_do_linetoscr_spr, lineno);
2931 		else
2932 #endif
2933 			do_color_changes (pfield_do_fill_line, dip_for_drawing->nr_sprites ? pfield_do_linetoscr_spr : pfield_do_linetoscr, lineno);
2934 
2935 		if (dh == dh_emerg)
2936 			memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_pixbytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
2937 
2938 		do_flush_line (vb, gfx_ypos);
2939 		if (do_double) {
2940 			if (dh == dh_emerg)
2941 				memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_pixbytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
2942 			else if (dh == dh_buf)
2943 				memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
2944 			if (need_genlock_data)
2945 				memcpy(row_map_genlock[follow_ypos], row_map_genlock[gfx_ypos], gfxvidinfo.drawbuffer.inwidth);
2946 			do_flush_line (vb, follow_ypos);
2947 		}
2948 
2949 		if (dip_for_drawing->nr_sprites)
2950 			pfield_erase_hborder_sprites ();
2951 
2952 	} else if (border > 0) { // border > 0: top or bottom border
2953 
2954 		bool dosprites = false;
2955 
2956 		adjust_drawing_colors (dp_for_drawing->ctable, 0);
2957 
2958 #ifdef AGA /* this makes things complex.. */
2959 		if (dp_for_drawing->bordersprite_seen && !ce_is_borderblank(colors_for_drawing.extra) && dip_for_drawing->nr_sprites) {
2960 			dosprites = true;
2961 			pfield_expand_dp_bplcon ();
2962 			pfield_init_linetoscr (true);
2963 			pfield_erase_vborder_sprites ();
2964 		}
2965 #endif
2966 
2967 		if (!dosprites && !have_color_changes) {
2968 			if (dp_for_drawing->plfleft < -1) {
2969 				// blanked border line
2970 				int tmp = hposblank;
2971 				hposblank = 1;
2972 				fill_line_border(lineno);
2973 				hposblank = tmp;
2974 			} else {
2975 				// normal border line
2976 				fill_line_border(lineno);
2977 			}
2978 
2979 			do_flush_line (vb, gfx_ypos);
2980 			if (do_double) {
2981 				if (dh == dh_buf) {
2982 					xlinebuffer = row_map[follow_ypos] - linetoscr_x_adjust_pixbytes;
2983 					xlinebuffer_genlock = row_map_genlock[follow_ypos] - linetoscr_x_adjust_pixels;
2984 					fill_line_border(lineno);
2985 				}
2986 				/* If dh == dh_line, do_flush_line will re-use the rendered line
2987 				* from linemem.  */
2988 				do_flush_line (vb, follow_ypos);
2989 			}
2990 			return;
2991 		}
2992 
2993 #ifdef AGA
2994 		if (dosprites) {
2995 
2996 			for (int i = 0; i < dip_for_drawing->nr_sprites; i++)
2997 				draw_sprites_aga (curr_sprite_entries + dip_for_drawing->first_sprite_entry + i, 1);
2998 			do_color_changes (pfield_do_linetoscr_bordersprite_aga, pfield_do_linetoscr_bordersprite_aga, lineno);
2999 #else
3000 		if (0) {
3001 #endif
3002 
3003 		} else {
3004 
3005 			playfield_start = visible_right_border;
3006 			playfield_end = visible_right_border;
3007 			do_color_changes (pfield_do_fill_line, pfield_do_fill_line, lineno);
3008 
3009 		}
3010 
3011 		if (dh == dh_emerg)
3012 			memcpy (row_map[gfx_ypos], xlinebuffer + linetoscr_x_adjust_pixbytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
3013 		do_flush_line (vb, gfx_ypos);
3014 		if (do_double) {
3015 			if (dh == dh_emerg)
3016 				memcpy (row_map[follow_ypos], xlinebuffer + linetoscr_x_adjust_pixbytes, gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
3017 			else if (dh == dh_buf)
3018 				memcpy (row_map[follow_ypos], row_map[gfx_ypos], gfxvidinfo.drawbuffer.pixbytes * gfxvidinfo.drawbuffer.inwidth);
3019 			if (need_genlock_data)
3020 				memcpy(row_map_genlock[follow_ypos], row_map_genlock[gfx_ypos], gfxvidinfo.drawbuffer.inwidth);
3021 			do_flush_line(vb, follow_ypos);
3022 		}
3023 
3024 	} else {
3025 
3026 		// top or bottom blanking region
3027 		int tmp = hposblank;
3028 		hposblank = 1;
3029 		fill_line_border(lineno);
3030 		hposblank = tmp;
3031 		do_flush_line(vb, gfx_ypos);
3032 
3033 	}
3034 }
3035 
3036 static void center_image (void)
3037 {
3038 	int prev_x_adjust = visible_left_border;
3039 	int prev_y_adjust = thisframe_y_adjust;
3040 
3041 	int w = gfxvidinfo.drawbuffer.inwidth;
3042 	if (currprefs.gfx_xcenter && !currprefs.gf[0].gfx_filter_autoscale && max_diwstop > 0) {
3043 
3044 		if (max_diwstop - min_diwstart < w && currprefs.gfx_xcenter == 2)
3045 			/* Try to center. */
3046 			visible_left_border = (max_diwstop - min_diwstart - w) / 2 + min_diwstart;
3047 		else
3048 			visible_left_border = max_diwstop - w - (max_diwstop - min_diwstart - w) / 2;
3049 		visible_left_border &= ~((xshift (1, lores_shift)) - 1);
3050 #if 1
3051 		if (!center_reset && !vertical_changed) {
3052 			/* Would the old value be good enough? If so, leave it as it is if we want to be clever. */
3053 			if (currprefs.gfx_xcenter == 2) {
3054 				if (visible_left_border < prev_x_adjust && prev_x_adjust < min_diwstart && min_diwstart - visible_left_border <= 32)
3055 					visible_left_border = prev_x_adjust;
3056 			}
3057 		}
3058 #endif
3059 	} else if (gfxvidinfo.drawbuffer.extrawidth) {
3060 		visible_left_border = max_diwlastword - w;
3061 		if (gfxvidinfo.drawbuffer.extrawidth > 0)
3062 			visible_left_border += gfxvidinfo.drawbuffer.extrawidth << currprefs.gfx_resolution;
3063 	} else {
3064 		if (gfxvidinfo.drawbuffer.inxoffset < 0) {
3065 			visible_left_border = 0;
3066 		} else {
3067 			visible_left_border = gfxvidinfo.drawbuffer.inxoffset - DISPLAY_LEFT_SHIFT;
3068 		}
3069 	}
3070 
3071 	if (visible_left_border > max_diwlastword - 32)
3072 		visible_left_border = max_diwlastword - 32;
3073 	if (visible_left_border < 0)
3074 		visible_left_border = 0;
3075 	visible_left_border &= ~((xshift (1, lores_shift)) - 1);
3076 
3077 	//write_log (_T("%d %d %d %d %d\n"), max_diwlastword, gfxvidinfo.drawbuffer.width, lores_shift, currprefs.gfx_resolution, visible_left_border);
3078 
3079 	linetoscr_x_adjust_pixels = visible_left_border;
3080 	linetoscr_x_adjust_pixbytes = linetoscr_x_adjust_pixels * gfxvidinfo.drawbuffer.pixbytes;
3081 
3082 	visible_right_border = visible_left_border + w;
3083 	if (visible_right_border > max_diwlastword)
3084 		visible_right_border = max_diwlastword;
3085 
3086 	int max_drawn_amiga_line_tmp = max_drawn_amiga_line;
3087 	if (max_drawn_amiga_line_tmp > gfxvidinfo.drawbuffer.inheight)
3088 		max_drawn_amiga_line_tmp = gfxvidinfo.drawbuffer.inheight;
3089 	max_drawn_amiga_line_tmp >>= linedbl;
3090 
3091 	thisframe_y_adjust = minfirstline;
3092 	if (currprefs.gfx_ycenter && thisframe_first_drawn_line >= 0 && !currprefs.gf[0].gfx_filter_autoscale) {
3093 
3094 		if (thisframe_last_drawn_line - thisframe_first_drawn_line < max_drawn_amiga_line_tmp && currprefs.gfx_ycenter == 2)
3095 			thisframe_y_adjust = (thisframe_last_drawn_line - thisframe_first_drawn_line - max_drawn_amiga_line_tmp) / 2 + thisframe_first_drawn_line;
3096 		else
3097 			thisframe_y_adjust = thisframe_first_drawn_line;
3098 #if 1
3099 		/* Would the old value be good enough? If so, leave it as it is if we want to be clever. */
3100 		if (!center_reset && !horizontal_changed) {
3101 			if (currprefs.gfx_ycenter == 2 && thisframe_y_adjust != prev_y_adjust) {
3102 				if (prev_y_adjust <= thisframe_first_drawn_line && prev_y_adjust + max_drawn_amiga_line_tmp > thisframe_last_drawn_line)
3103 					thisframe_y_adjust = prev_y_adjust;
3104 			}
3105 		}
3106 #endif
3107 	}
3108 
3109 	/* Make sure the value makes sense */
3110 	if (thisframe_y_adjust + max_drawn_amiga_line_tmp > maxvpos + maxvpos / 2)
3111 		thisframe_y_adjust = maxvpos + maxvpos / 2 - max_drawn_amiga_line_tmp;
3112 	if (thisframe_y_adjust < 0)
3113 		thisframe_y_adjust = 0;
3114 
3115 	thisframe_y_adjust_real = thisframe_y_adjust << linedbl;
3116 	max_ypos_thisframe = (maxvpos_display - minfirstline + 1) << linedbl;
3117 
3118 	if (prev_x_adjust != visible_left_border || prev_y_adjust != thisframe_y_adjust) {
3119 		int redraw = interlace_seen > 0 && linedbl ? 2 : 1;
3120 		if (redraw > frame_redraw_necessary)
3121 			frame_redraw_necessary = redraw;
3122 	}
3123 
3124 	max_diwstop = 0;
3125 	min_diwstart = MAX_STOP;
3126 
3127 	gfxvidinfo.drawbuffer.xoffset = (DISPLAY_LEFT_SHIFT << RES_MAX) + (visible_left_border << (RES_MAX - currprefs.gfx_resolution));
3128 	gfxvidinfo.drawbuffer.yoffset = thisframe_y_adjust << VRES_MAX;
3129 
3130 	center_reset = false;
3131 	horizontal_changed = false;
3132 	vertical_changed = false;
3133 }
3134 
3135 static int frame_res_cnt;
3136 static int autoswitch_old_resolution;
3137 static void init_drawing_frame (void)
3138 {
3139 	int i, maxline;
3140 	static int frame_res_old;
3141 
3142 	if (currprefs.gfx_resolution == changed_prefs.gfx_resolution && lines_count > 0) {
3143 		int largest_count = 0;
3144 		int largest_count_res = 0;
3145 		int largest_res = 0;
3146 		for (int i = 0; i <= RES_MAX; i++) {
3147 			if (resolution_count[i])
3148 				largest_res = i;
3149 			if (resolution_count[i] >= largest_count) {
3150 				largest_count = resolution_count[i];
3151 				largest_count_res = i;
3152 			}
3153 		}
3154 
3155 		if (currprefs.gfx_autoresolution_vga && programmedmode && gfxvidinfo.gfx_resolution_reserved >= RES_HIRES && gfxvidinfo.gfx_vresolution_reserved >= VRES_DOUBLE) {
3156 			if (largest_res == RES_SUPERHIRES && (gfxvidinfo.gfx_resolution_reserved < RES_SUPERHIRES || gfxvidinfo.gfx_vresolution_reserved < 1)) {
3157 				// enable full doubling/superhires support if programmed mode. It may be "half-width" only and may fit in normal display window.
3158 				gfxvidinfo.gfx_resolution_reserved = RES_SUPERHIRES;
3159 				gfxvidinfo.gfx_vresolution_reserved = VRES_DOUBLE;
3160 				graphics_reset(false);
3161 			}
3162 			int newres = largest_res;
3163 			if (htotal < 190)
3164 				newres = largest_res + 1;
3165 			if (newres < RES_HIRES)
3166 				newres = RES_HIRES;
3167 			if (newres > RES_MAX)
3168 				newres = RES_MAX;
3169 			if (changed_prefs.gfx_resolution != newres) {
3170 				autoswitch_old_resolution = RES_HIRES;
3171 				write_log(_T("Programmed mode autores = %d -> %d (%d)\n"), changed_prefs.gfx_resolution, newres, largest_res);
3172 				changed_prefs.gfx_resolution = newres;
3173 				set_config_changed();
3174 				return;
3175 			}
3176 		} else if (autoswitch_old_resolution == RES_HIRES) {
3177 			autoswitch_old_resolution = 0;
3178 			if (changed_prefs.gfx_resolution != RES_HIRES) {
3179 				changed_prefs.gfx_resolution = RES_HIRES;
3180 				set_config_changed();
3181 				return;
3182 			}
3183 		}
3184 
3185 		if (currprefs.gfx_autoresolution) {
3186 			int frame_res_detected;
3187 			int frame_res_lace_detected = frame_res_lace;
3188 
3189 			if (currprefs.gfx_autoresolution == 1 || currprefs.gfx_autoresolution >= 100)
3190 				frame_res_detected = largest_res;
3191 			else if (largest_count * 100 / lines_count >= currprefs.gfx_autoresolution)
3192 				frame_res_detected = largest_count_res;
3193 			else
3194 				frame_res_detected = largest_count_res - 1;
3195 			if (frame_res_detected < 0)
3196 				frame_res_detected = 0;
3197 	#if 0
3198 			static int delay;
3199 			delay--;
3200 			if (delay < 0) {
3201 				delay = 50;
3202 				write_log (_T("%d %d, %d %d %d, %d %d, %d %d\n"), currprefs.gfx_autoresolution, lines_count, resolution_count[0], resolution_count[1], resolution_count[2],
3203 					largest_count, largest_count_res, frame_res_detected, frame_res_lace_detected);
3204 			}
3205 	#endif
3206 			if (frame_res_detected >= 0 && frame_res_lace_detected >= 0) {
3207 				if (frame_res_cnt > 0 && frame_res_old == frame_res_detected * 2 + frame_res_lace_detected) {
3208 					frame_res_cnt--;
3209 					if (frame_res_cnt == 0) {
3210 						int m = frame_res_detected * 2 + frame_res_lace_detected;
3211 						struct wh *dst = currprefs.gfx_apmode[0].gfx_fullscreen ? &changed_prefs.gfx_size_fs : &changed_prefs.gfx_size_win;
3212 						while (m < 3 * 2) {
3213 							struct wh *src = currprefs.gfx_apmode[0].gfx_fullscreen ? &currprefs.gfx_size_fs_xtra[m] : &currprefs.gfx_size_win_xtra[m];
3214 							if ((src->width > 0 && src->height > 0) || (currprefs.gfx_api || currprefs.gf[0].gfx_filter > 0)) {
3215 								int nr = m >> 1;
3216 								int nl = (m & 1) == 0 ? 0 : 1;
3217 								int nr_o = nr;
3218 								int nl_o = nl;
3219 
3220 								if (currprefs.gfx_autoresolution >= 100 && nl == 0 && nr > 0) {
3221 									nl = 1;
3222 								}
3223 
3224 								if (currprefs.gfx_autoresolution_minh < 0) {
3225 									if (nr < nl)
3226 										nr = nl;
3227 								} else if (nr < currprefs.gfx_autoresolution_minh) {
3228 									nr = currprefs.gfx_autoresolution_minh;
3229 								}
3230 								if (currprefs.gfx_autoresolution_minv < 0) {
3231 									if (nl < nr)
3232 										nl = nr;
3233 								} else if (nl < currprefs.gfx_autoresolution_minv) {
3234 									nl = currprefs.gfx_autoresolution_minv;
3235 								}
3236 
3237 								if (nr > gfxvidinfo.gfx_resolution_reserved)
3238 									nr = gfxvidinfo.gfx_resolution_reserved;
3239 								if (nl > gfxvidinfo.gfx_vresolution_reserved)
3240 									nl = gfxvidinfo.gfx_vresolution_reserved;
3241 
3242 								if (changed_prefs.gfx_resolution != nr || changed_prefs.gfx_vresolution != nl) {
3243 									changed_prefs.gfx_resolution = nr;
3244 									changed_prefs.gfx_vresolution = nl;
3245 
3246 									write_log (_T("RES -> %d (%d) LINE -> %d (%d) (%d - %d, %d - %d)\n"), nr, nr_o, nl, nl_o,
3247 										currprefs.gfx_autoresolution_minh, currprefs.gfx_autoresolution_minv,
3248 										gfxvidinfo.gfx_resolution_reserved, gfxvidinfo.gfx_vresolution_reserved);
3249 									set_config_changed ();
3250 									//activate_debugger ();
3251 								}
3252 								if (src->width > 0 && src->height > 0) {
3253 									if (memcmp (dst, src, sizeof *dst)) {
3254 										*dst = *src;
3255 										set_config_changed ();
3256 									}
3257 								}
3258 								break;
3259 							}
3260 							m++;
3261 						}
3262 						frame_res_cnt = currprefs.gfx_autoresolution_delay;
3263 					}
3264 				} else {
3265 					frame_res_old = frame_res_detected * 2 + frame_res_lace_detected;
3266 					frame_res_cnt = currprefs.gfx_autoresolution_delay;
3267 					if (frame_res_cnt <= 0)
3268 						frame_res_cnt = 1;
3269 				}
3270 			}
3271 		}
3272 	}
3273 	for (int i = 0; i <= RES_MAX; i++)
3274 		resolution_count[i] = 0;
3275 	lines_count = 0;
3276 	frame_res = -1;
3277 	frame_res_lace = 0;
3278 
3279 	if (can_use_lores > AUTO_LORES_FRAMES && 0) {
3280 		lores_factor = 1;
3281 		lores_set(0);
3282 	} else {
3283 		can_use_lores++;
3284 		lores_reset();
3285 	}
3286 
3287 	init_hardware_for_drawing_frame ();
3288 
3289 	if (thisframe_first_drawn_line < 0)
3290 		thisframe_first_drawn_line = minfirstline;
3291 	if (thisframe_first_drawn_line > thisframe_last_drawn_line)
3292 		thisframe_last_drawn_line = thisframe_first_drawn_line;
3293 
3294 	maxline = ((maxvpos_display + 1) << linedbl) + 2;
3295 #ifdef SMART_UPDATE
3296 	for (i = 0; i < maxline; i++) {
3297 		int ls = linestate[i];
3298 		switch (ls) {
3299 		case LINE_DONE_AS_PREVIOUS:
3300 			linestate[i] = LINE_REMEMBERED_AS_PREVIOUS;
3301 			break;
3302 		case LINE_REMEMBERED_AS_BLACK:
3303 			break;
3304 		default:
3305 			linestate[i] = LINE_UNDECIDED;
3306 			break;
3307 		}
3308 	}
3309 #else
3310 	memset (linestate, LINE_UNDECIDED, maxline);
3311 #endif
3312 	last_drawn_line = 0;
3313 	first_drawn_line = 32767;
3314 
3315 	first_block_line = last_block_line = NO_BLOCK;
3316 	if (frame_redraw_necessary) {
3317 		reset_decision_table();
3318 		custom_frame_redraw_necessary = 1;
3319 		frame_redraw_necessary--;
3320 	} else {
3321 		custom_frame_redraw_necessary = 0;
3322 	}
3323 
3324 	center_image ();
3325 
3326 	thisframe_first_drawn_line = -1;
3327 	thisframe_last_drawn_line = -1;
3328 
3329 	drawing_color_matches = -1;
3330 }
3331 
3332 static int lightpen_y1, lightpen_y2;
3333 static int statusbar_y1, statusbar_y2;
3334 
3335 void putpixel (uae_u8 *buf, int bpp, int x, xcolnr c8, int opaq)
3336 {
3337 	if (x <= 0)
3338 		return;
3339 
3340 	switch (bpp) {
3341 	case 1:
3342 		buf[x] = (uae_u8)c8;
3343 		break;
3344 	case 2:
3345 		{
3346 			uae_u16 *p = (uae_u16*)buf + x;
3347 			*p = (uae_u16)c8;
3348 			break;
3349 		}
3350 	case 3:
3351 		/* no 24 bit yet */
3352 		break;
3353 	case 4:
3354 		{
3355 			int i;
3356 			if (1 || opaq || currprefs.gf[0].gfx_filter == 0) {
3357 				uae_u32 *p = (uae_u32*)buf + x;
3358 				*p = c8;
3359 			} else {
3360 				for (i = 0; i < 4; i++) {
3361 					int v1 = buf[i + bpp * x];
3362 					int v2 = (c8 >> (i * 8)) & 255;
3363 					v1 = (v1 * 2 + v2 * 3) / 5;
3364 					if (v1 > 255)
3365 						v1 = 255;
3366 					buf[i + bpp * x] = v1;
3367 				}
3368 			}
3369 			break;
3370 		}
3371 	}
3372 }
3373 
3374 static uae_u8 *status_line_ptr(int line)
3375 {
3376 	int y;
3377 
3378 	y = line - (gfxvidinfo.drawbuffer.outheight - TD_TOTAL_HEIGHT);
3379 	xlinebuffer = gfxvidinfo.drawbuffer.linemem;
3380 	if (xlinebuffer == 0)
3381 		xlinebuffer = row_map[line];
3382 	xlinebuffer_genlock = row_map_genlock[line];
3383 	return xlinebuffer;
3384 }
3385 
3386 static void draw_status_line (int line, int statusy)
3387 {
3388 	uae_u8 *buf = status_line_ptr(line);
3389 	if (!buf)
3390 		return;
3391 	if (statusy < 0)
3392 		statusline_render(buf, gfxvidinfo.drawbuffer.pixbytes, gfxvidinfo.drawbuffer.rowbytes, gfxvidinfo.drawbuffer.outwidth, TD_TOTAL_HEIGHT, xredcolors, xgreencolors, xbluecolors, NULL);
3393 	else
3394 		draw_status_line_single(buf, gfxvidinfo.drawbuffer.pixbytes, statusy, gfxvidinfo.drawbuffer.outwidth, xredcolors, xgreencolors, xbluecolors, NULL);
3395 }
3396 
3397 static void draw_debug_status_line (int line)
3398 {
3399 	xlinebuffer = gfxvidinfo.drawbuffer.linemem;
3400 	if (xlinebuffer == 0)
3401 		xlinebuffer = row_map[line];
3402 	xlinebuffer_genlock = row_map_genlock[line];
3403 	debug_draw(xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, line, gfxvidinfo.drawbuffer.outwidth, gfxvidinfo.drawbuffer.outheight, xredcolors, xgreencolors, xbluecolors);
3404 }
3405 
3406 #define LIGHTPEN_HEIGHT 12
3407 #define LIGHTPEN_WIDTH 17
3408 
3409 static const char *lightpen_cursor = {
3410 	"------.....------"
3411 	"------.xxx.------"
3412 	"------.xxx.------"
3413 	"------.xxx.------"
3414 	".......xxx......."
3415 	".xxxxxxxxxxxxxxx."
3416 	".xxxxxxxxxxxxxxx."
3417 	".......xxx......."
3418 	"------.xxx.------"
3419 	"------.xxx.------"
3420 	"------.xxx.------"
3421 	"------.....------"
3422 };
3423 
3424 static void draw_lightpen_cursor (int x, int y, int line, int onscreen)
3425 {
3426 	int i;
3427 	const char *p;
3428 	int color1 = onscreen ? 0xff0 : 0xf00;
3429 	int color2 = 0x000;
3430 
3431 	xlinebuffer = gfxvidinfo.drawbuffer.linemem;
3432 	if (xlinebuffer == 0)
3433 		xlinebuffer = row_map[line];
3434 	xlinebuffer_genlock = row_map_genlock[line];
3435 
3436 	p = lightpen_cursor + y * LIGHTPEN_WIDTH;
3437 	for (i = 0; i < LIGHTPEN_WIDTH; i++) {
3438 		int xx = x + i - LIGHTPEN_WIDTH / 2;
3439 		if (*p != '-' && xx >= 0 && xx < gfxvidinfo.drawbuffer.outwidth)
3440 			putpixel (xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, xx, *p == 'x' ? xcolors[color1] : xcolors[color2], 1);
3441 		p++;
3442 	}
3443 }
3444 
3445 static void lightpen_update (struct vidbuffer *vb)
3446 {
3447 	int i;
3448 
3449 	if (lightpen_x < LIGHTPEN_WIDTH + 1)
3450 		lightpen_x = LIGHTPEN_WIDTH + 1;
3451 	if (lightpen_x >= gfxvidinfo.drawbuffer.inwidth - LIGHTPEN_WIDTH - 1)
3452 		lightpen_x = gfxvidinfo.drawbuffer.inwidth - LIGHTPEN_WIDTH - 2;
3453 	if (lightpen_y < LIGHTPEN_HEIGHT + 1)
3454 		lightpen_y = LIGHTPEN_HEIGHT + 1;
3455 	if (lightpen_y >= gfxvidinfo.drawbuffer.inheight - LIGHTPEN_HEIGHT - 1)
3456 		lightpen_y = gfxvidinfo.drawbuffer.inheight - LIGHTPEN_HEIGHT - 2;
3457 	if (lightpen_y >= max_ypos_thisframe - LIGHTPEN_HEIGHT - 1)
3458 		lightpen_y = max_ypos_thisframe - LIGHTPEN_HEIGHT - 2;
3459 
3460 	lightpen_cx = (((lightpen_x + visible_left_border) >> lores_shift) >> 1) + DISPLAY_LEFT_SHIFT - DIW_DDF_OFFSET;
3461 
3462 	lightpen_cy = lightpen_y;
3463 	lightpen_cy >>= linedbl;
3464 	lightpen_cy += minfirstline;
3465 
3466 	if (lightpen_cx < 0x18)
3467 		lightpen_cx = 0x18;
3468 	if (lightpen_cx >= maxhpos)
3469 		lightpen_cx -= maxhpos;
3470 	if (lightpen_cy < minfirstline)
3471 		lightpen_cy = minfirstline;
3472 	if (lightpen_cy >= maxvpos)
3473 		lightpen_cy = maxvpos - 1;
3474 
3475 	for (i = 0; i < LIGHTPEN_HEIGHT; i++) {
3476 		int line = lightpen_y + i - LIGHTPEN_HEIGHT / 2;
3477 		if (line >= 0 || line < max_ypos_thisframe) {
3478 			if (lightpen_active > 0)
3479 				draw_lightpen_cursor (lightpen_x, i, line, lightpen_cx > 0);
3480 			flush_line (vb, line);
3481 		}
3482 	}
3483 	lightpen_y1 = lightpen_y - LIGHTPEN_HEIGHT / 2 - 1 + min_ypos_for_screen;
3484 	lightpen_y2 = lightpen_y1 + LIGHTPEN_HEIGHT + 2;
3485 
3486 	if (lightpen_active < 0)
3487 		lightpen_active = 0;
3488 }
3489 
3490 static void refresh_indicator_init(void)
3491 {
3492 	xfree(refresh_indicator_buffer);
3493 	refresh_indicator_buffer = NULL;
3494 	xfree(refresh_indicator_changed);
3495 	refresh_indicator_changed = NULL;
3496 	xfree(refresh_indicator_changed_prev);
3497 	refresh_indicator_changed_prev = NULL;
3498 
3499 	if (!currprefs.refresh_indicator)
3500 		return;
3501 
3502 	refresh_indicator_height = 600;
3503 	refresh_indicator_buffer = xcalloc(uae_u8, MAX_PIXELS_PER_LINE * 2 * refresh_indicator_height);
3504 	refresh_indicator_changed = xcalloc(uae_u8, refresh_indicator_height);
3505 	refresh_indicator_changed_prev = xcalloc(uae_u8, refresh_indicator_height);
3506 }
3507 
3508 static const int refresh_indicator_colors[] = { 0x777, 0x0f0, 0x00f, 0xff0, 0xf0f };
3509 
3510 static void refresh_indicator_update(struct vidbuffer *vb)
3511 {
3512 	for (int i = 0; i < max_ypos_thisframe; i++) {
3513 		int i1 = i + min_ypos_for_screen;
3514 		int line = i + thisframe_y_adjust_real;
3515 		int whereline = amiga2aspect_line_map[i1];
3516 		int wherenext = amiga2aspect_line_map[i1 + 1];
3517 
3518 		if (whereline >= vb->inheight)
3519 			break;
3520 		if (whereline < 0)
3521 			continue;
3522 		if (line >= refresh_indicator_height)
3523 			break;
3524 
3525 		xlinebuffer = row_map[whereline];
3526 		uae_u8 pixel = refresh_indicator_changed_prev[line];
3527 		if (wherenext >= 0) {
3528 			pixel = refresh_indicator_changed_prev[line & ~1];
3529 		}
3530 
3531 		int color1 = 0;
3532 		int color2 = 0;
3533 		if (pixel <= 4) {
3534 			color1 = color2 = refresh_indicator_colors[pixel];
3535 		} else if (pixel <= 8) {
3536 			color2 = refresh_indicator_colors[pixel - 5];
3537 		}
3538 		for (int x = 0; x < 8; x++) {
3539 			putpixel(xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, x, xcolors[color1], 1);
3540 		}
3541 		for (int x = 8; x < 16; x++) {
3542 			putpixel(xlinebuffer, gfxvidinfo.drawbuffer.pixbytes, x, xcolors[color2], 1);
3543 		}
3544 	}
3545 }
3546 
3547 struct vidbuffer *xvbin, *xvbout;
3548 
3549 #define LARGEST_LINE_DEBUG 0
3550 
3551 static void draw_frame2 (struct vidbuffer *vbin, struct vidbuffer *vbout)
3552 {
3553 	int i;
3554 
3555 	xvbin = vbin;
3556 	xvbout = vbout;
3557 
3558 #if LARGEST_LINE_DEBUG
3559 	int largest = 0;
3560 #endif
3561 	for (i = 0; i < max_ypos_thisframe; i++) {
3562 		int i1 = i + min_ypos_for_screen;
3563 		int line = i + thisframe_y_adjust_real;
3564 		int whereline = amiga2aspect_line_map[i1];
3565 		int wherenext = amiga2aspect_line_map[i1 + 1];
3566 
3567 		if (whereline >= vbin->inheight)
3568 			break;
3569 		if (whereline < 0)
3570 			continue;
3571 
3572 #if LARGEST_LINE_DEBUG
3573 		if (largest < whereline)
3574 			largest = whereline;
3575 #endif
3576 
3577 		hposblank = 0;
3578 		pfield_draw_line(vbout, line, whereline, wherenext);
3579 	}
3580 
3581 #if LARGEST_LINE_DEBUG
3582 	write_log (_T("%d\n"), largest);
3583 #endif
3584 }
3585 
3586 bool draw_frame (struct vidbuffer *vb)
3587 {
3588 	uae_u8 oldstate[LINESTATE_SIZE];
3589 	struct vidbuffer oldvb;
3590 
3591 	memcpy (&oldvb, &gfxvidinfo.drawbuffer, sizeof (struct vidbuffer));
3592 	memcpy (&gfxvidinfo.drawbuffer, vb, sizeof (struct vidbuffer));
3593 	clearbuffer (vb);
3594 	init_row_map ();
3595 	memcpy (oldstate, linestate, LINESTATE_SIZE);
3596 	for (int i = 0; i < LINESTATE_SIZE; i++) {
3597 		uae_u8 v = linestate[i];
3598 		if (v == LINE_REMEMBERED_AS_PREVIOUS) {
3599 			linestate[i - 1] = LINE_DECIDED_DOUBLE;
3600 			v = LINE_AS_PREVIOUS;
3601 		} else if (v == LINE_DONE_AS_PREVIOUS) {
3602 			linestate[i - 1] = LINE_DECIDED_DOUBLE;
3603 			v = LINE_AS_PREVIOUS;
3604 		} else if (v == LINE_REMEMBERED_AS_BLACK) {
3605 			v = LINE_BLACK;
3606 		} else if (v == LINE_DONE) {
3607 			v = LINE_DECIDED;
3608 		}
3609 //		if (i < maxvpos)
3610 //			write_log (_T("%d: %d -> %d\n"), i, linestate[i], v);
3611 		linestate[i] = v;
3612 	}
3613 	last_drawn_line = 0;
3614 	first_drawn_line = 32767;
3615 	drawing_color_matches = -1;
3616 	draw_frame2 (vb, NULL);
3617 	last_drawn_line = 0;
3618 	first_drawn_line = 32767;
3619 	drawing_color_matches = -1;
3620 	memcpy (linestate, oldstate, LINESTATE_SIZE);
3621 	memcpy (&gfxvidinfo.drawbuffer, &oldvb, sizeof (struct vidbuffer));
3622 	init_row_map ();
3623 	return true;
3624 }
3625 
3626 static void setnativeposition(struct vidbuffer *vb)
3627 {
3628 	vb->inwidth = gfxvidinfo.drawbuffer.inwidth;
3629 	vb->inheight = gfxvidinfo.drawbuffer.inheight;
3630 	vb->inwidth2 = gfxvidinfo.drawbuffer.inwidth2;
3631 	vb->inheight2 = gfxvidinfo.drawbuffer.inheight2;
3632 	vb->outwidth = gfxvidinfo.drawbuffer.outwidth;
3633 	vb->outheight = gfxvidinfo.drawbuffer.outheight;
3634 }
3635 
3636 static void setspecialmonitorpos(struct vidbuffer *vb)
3637 {
3638 	vb->extrawidth = gfxvidinfo.drawbuffer.extrawidth;
3639 	vb->xoffset = gfxvidinfo.drawbuffer.xoffset;
3640 	vb->yoffset = gfxvidinfo.drawbuffer.yoffset;
3641 	vb->inxoffset = gfxvidinfo.drawbuffer.inxoffset;
3642 	vb->inyoffset = gfxvidinfo.drawbuffer.inyoffset;
3643 }
3644 
3645 static void finish_drawing_frame (void)
3646 {
3647 	int i;
3648 	bool didflush = false;
3649 	struct vidbuffer *vb = &gfxvidinfo.drawbuffer;
3650 
3651 	gfxvidinfo.outbuffer = vb;
3652 
3653 	if (! lockscr (vb, false)) {
3654 		notice_screen_contents_lost ();
3655 		return;
3656 	}
3657 
3658 #ifndef SMART_UPDATE
3659 	/* @@@ This isn't exactly right yet. FIXME */
3660 	if (!interlace_seen)
3661 		do_flush_screen (first_drawn_line, last_drawn_line);
3662 	else
3663 		unlockscr ();
3664 	return;
3665 #endif
3666 
3667 	draw_frame2 (vb, vb);
3668 
3669 	if (currprefs.leds_on_screen && ((currprefs.leds_on_screen & STATUSLINE_CHIPSET) && !(currprefs.leds_on_screen & STATUSLINE_TARGET))) {
3670 		int slx, sly;
3671 		statusline_getpos(&slx, &sly, vb->outwidth, vb->outheight);
3672 		statusbar_y1 = sly + min_ypos_for_screen - 1;
3673 		statusbar_y2 = statusbar_y1 + TD_TOTAL_HEIGHT + 1;
3674 		draw_status_line(sly, -1);
3675 		for (i = 0; i < TD_TOTAL_HEIGHT; i++) {
3676 			int line = sly + i;
3677 			draw_status_line (line, i);
3678 			do_flush_line (vb, line);
3679 		}
3680 	}
3681 	if (debug_dma > 1 || debug_heatmap > 1) {
3682 		for (i = 0; i < vb->outheight; i++) {
3683 			int line = i;
3684 			draw_debug_status_line (line);
3685 			do_flush_line (vb, line);
3686 		}
3687 	}
3688 
3689 	if (lightpen_active)
3690 		lightpen_update (vb);
3691 	if (refresh_indicator_buffer)
3692 		refresh_indicator_update(vb);
3693 
3694 	if (currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated) {
3695 		setspecialmonitorpos(&gfxvidinfo.tempbuffer);
3696 		if (init_genlock_data != specialmonitor_need_genlock()) {
3697 			init_genlock_data = specialmonitor_need_genlock();
3698 			init_row_map();
3699 		}
3700 		if (emulate_specialmonitors (vb, &gfxvidinfo.tempbuffer)) {
3701 			vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer;
3702 			if (vb->nativepositioning)
3703 				setnativeposition(vb);
3704 			gfxvidinfo.drawbuffer.tempbufferinuse = true;
3705 			need_genlock_data = specialmonitor_need_genlock();
3706 			if (!specialmonitoron) {
3707 				compute_framesync();
3708 			}
3709 			specialmonitoron = true;
3710 			pfield_set_linetoscr();
3711 			do_flush_screen (vb, 0, vb->outheight);
3712 			didflush = true;
3713 		} else {
3714 			pfield_set_linetoscr();
3715 			need_genlock_data = false;
3716 			if (specialmonitoron || gfxvidinfo.drawbuffer.tempbufferinuse) {
3717 				gfxvidinfo.drawbuffer.tempbufferinuse = false;
3718 				specialmonitoron = false;
3719 				compute_framesync();
3720 			}
3721 		}
3722 	}
3723 
3724 	if (currprefs.genlock_image && !currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated && currprefs.genlock) {
3725 		pfield_set_linetoscr();
3726 		setspecialmonitorpos(&gfxvidinfo.tempbuffer);
3727 		if (init_genlock_data != specialmonitor_need_genlock()) {
3728 			need_genlock_data = init_genlock_data = specialmonitor_need_genlock();
3729 			init_row_map();
3730 		}
3731 		emulate_genlock(vb, &gfxvidinfo.tempbuffer);
3732 		vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer;
3733 		if (vb->nativepositioning)
3734 			setnativeposition(vb);
3735 		gfxvidinfo.drawbuffer.tempbufferinuse = true;
3736 		do_flush_screen(vb, 0, vb->outheight);
3737 		didflush = true;
3738 	}
3739 
3740 	if (!currprefs.monitoremu && gfxvidinfo.tempbuffer.bufmem_allocated && currprefs.cs_cd32fmv) {
3741 		if (cd32_fmv_active) {
3742 			cd32_fmv_genlock(vb, &gfxvidinfo.tempbuffer);
3743 			vb = gfxvidinfo.outbuffer = &gfxvidinfo.tempbuffer;
3744 			setnativeposition(vb);
3745 			gfxvidinfo.drawbuffer.tempbufferinuse = true;
3746 			do_flush_screen(vb, 0, vb->outheight);
3747 			didflush = true;
3748 		} else {
3749 			gfxvidinfo.drawbuffer.tempbufferinuse = false;
3750 		}
3751 	}
3752 
3753 	if (!didflush)
3754 		do_flush_screen (vb, first_drawn_line, last_drawn_line);
3755 }
3756 
3757 void hardware_line_completed (int lineno)
3758 {
3759 #ifndef SMART_UPDATE
3760 	{
3761 		int i, where;
3762 		/* l is the line that has been finished for drawing. */
3763 		i = lineno - thisframe_y_adjust_real;
3764 		if (i >= 0 && i < max_ypos_thisframe) {
3765 			where = amiga2aspect_line_map[i+min_ypos_for_screen];
3766 			if (where < gfxvidinfo.drawbuffer.outheight && where >= 0)
3767 				pfield_draw_line (lineno, where, amiga2aspect_line_map[i+min_ypos_for_screen+1]);
3768 		}
3769 	}
3770 #endif
3771 }
3772 
3773 static void check_picasso (void)
3774 {
3775 #ifdef PICASSO96
3776 	if (picasso_on && picasso_redraw_necessary)
3777 		picasso_refresh ();
3778 	picasso_redraw_necessary = 0;
3779 
3780 	if (picasso_requested_on == picasso_on)
3781 		return;
3782 
3783 	picasso_on = picasso_requested_on;
3784 
3785 	if (!picasso_on)
3786 		clear_inhibit_frame (IHF_PICASSO);
3787 	else
3788 		set_inhibit_frame (IHF_PICASSO);
3789 
3790 	gfx_set_picasso_state (picasso_on);
3791 	picasso_enablescreen (picasso_requested_on);
3792 
3793 	notice_screen_contents_lost ();
3794 	notice_new_xcolors ();
3795 	count_frame ();
3796 #endif
3797 }
3798 
3799 void redraw_frame (void)
3800 {
3801 	last_drawn_line = 0;
3802 	first_drawn_line = 32767;
3803 	finish_drawing_frame ();
3804 	flush_screen (gfxvidinfo.inbuffer, 0, 0);
3805 }
3806 
3807 bool vsync_handle_check (void)
3808 {
3809 	int changed = check_prefs_changed_gfx ();
3810 	if (changed > 0) {
3811 		reset_drawing ();
3812 		init_row_map ();
3813 		init_aspect_maps ();
3814 		notice_screen_contents_lost ();
3815 		notice_new_xcolors ();
3816 	} else if (changed < 0) {
3817 		reset_drawing ();
3818 		init_row_map ();
3819 		init_aspect_maps ();
3820 		notice_screen_contents_lost ();
3821 		notice_new_xcolors ();
3822 	}
3823 	check_prefs_changed_cd ();
3824 	check_prefs_changed_audio ();
3825 	check_prefs_changed_custom ();
3826 	check_prefs_changed_cpu ();
3827 	check_picasso ();
3828 	return changed != 0;
3829 }
3830 
3831 void vsync_handle_redraw (int long_field, int lof_changed, uae_u16 bplcon0p, uae_u16 bplcon3p)
3832 {
3833 	last_redraw_point++;
3834 	if (lof_changed || interlace_seen <= 0 || (currprefs.gfx_iscanlines && interlace_seen > 0) || last_redraw_point >= 2 || long_field || doublescan < 0) {
3835 		last_redraw_point = 0;
3836 
3837 		if (framecnt == 0)
3838 			finish_drawing_frame ();
3839 #if 0
3840 		if (interlace_seen > 0) {
3841 			interlace_seen = -1;
3842 		} else if (interlace_seen == -1) {
3843 			interlace_seen = 0;
3844 			if (currprefs.gfx_scandoubler && currprefs.gfx_vresolution)
3845 				notice_screen_contents_lost ();
3846 		}
3847 #endif
3848 
3849 		if (quit_program < 0) {
3850 #ifdef SAVESTATE
3851 			if (!savestate_state) {
3852 				if (currprefs.quitstatefile[0]) {
3853 					savestate_initsave (currprefs.quitstatefile, 1, 1, true);
3854 					save_state (currprefs.quitstatefile, _T(""));
3855 				}
3856 			}
3857 #endif
3858 			quit_program = -quit_program;
3859 			set_inhibit_frame (IHF_QUIT_PROGRAM);
3860 			set_special(SPCFLAG_BRK | SPCFLAG_MODE_CHANGE);
3861 			return;
3862 		}
3863 
3864 		count_frame ();
3865 
3866 		if (framecnt == 0)
3867 			init_drawing_frame ();
3868 		else if (currprefs.cpu_cycle_exact)
3869 			init_hardware_for_drawing_frame ();
3870 	} else {
3871 		if (isvsync_chipset ())
3872 			flush_screen (gfxvidinfo.inbuffer, 0, 0); /* vsync mode */
3873 	}
3874 
3875 	gui_flicker_led (-1, 0, 0);
3876 #ifdef AVIOUTPUT
3877 	if (!picasso_on)
3878 		frame_drawn ();
3879 #endif
3880 }
3881 
3882 void hsync_record_line_state (int lineno, enum nln_how how, int changed)
3883 {
3884 	uae_u8 *state;
3885 
3886 	if (framecnt != 0)
3887 		return;
3888 
3889 	state = linestate + lineno;
3890 	changed |= frame_redraw_necessary != 0 || refresh_indicator_buffer != NULL ||
3891 		((lineno >= lightpen_y1 && lineno < lightpen_y2) ||
3892 		(lineno >= statusbar_y1 && lineno < statusbar_y2));
3893 
3894 	switch (how) {
3895 	case nln_normal:
3896 		*state = changed ? LINE_DECIDED : LINE_DONE;
3897 		break;
3898 	case nln_doubled:
3899 		*state = changed ? LINE_DECIDED_DOUBLE : LINE_DONE;
3900 		changed |= state[1] != LINE_REMEMBERED_AS_PREVIOUS;
3901 		state[1] = changed ? LINE_AS_PREVIOUS : LINE_DONE_AS_PREVIOUS;
3902 		break;
3903 	case nln_nblack:
3904 		*state = changed ? LINE_DECIDED : LINE_DONE;
3905 		if (state[1] != LINE_REMEMBERED_AS_BLACK) {
3906 			state[1] = LINE_BLACK;
3907 		}
3908 		break;
3909 	case nln_lower:
3910 		if (lineno > 0 && state[-1] == LINE_UNDECIDED) {
3911 			state[-1] = LINE_DECIDED; //LINE_BLACK;
3912 		}
3913 		*state = changed ? LINE_DECIDED : LINE_DONE;
3914 		break;
3915 	case nln_upper:
3916 		*state = changed ? LINE_DECIDED : LINE_DONE;
3917 		if (state[1] == LINE_UNDECIDED
3918 			|| state[1] == LINE_REMEMBERED_AS_PREVIOUS
3919 			|| state[1] == LINE_AS_PREVIOUS)
3920 			state[1] = LINE_DECIDED; //LINE_BLACK;
3921 		break;
3922 	case nln_lower_black_always:
3923 		state[1] = LINE_BLACK;
3924 		*state = LINE_DECIDED;
3925 //		if (lineno == (maxvpos + lof_store) * 2 - 1)
3926 //			*state = LINE_BLACK;
3927 		break;
3928 	case nln_lower_black:
3929 		changed |= state[0] != LINE_DONE;
3930 		state[1] = LINE_DONE;
3931 		*state = changed ? LINE_DECIDED : LINE_DONE;
3932 //		if (lineno == (maxvpos + lof_store) * 2 - 1)
3933 //			*state = LINE_BLACK;
3934 		break;
3935 	case nln_upper_black_always:
3936 		*state = LINE_DECIDED;
3937 		if (lineno > 0) {
3938 			state[-1] = LINE_BLACK;
3939 		}
3940 		if (!interlace_seen && lineno == (maxvpos + lof_store) * 2 - 2) {
3941 			state[1] = LINE_BLACK;
3942 		}
3943 		break;
3944 	case nln_upper_black:
3945 		changed |= state[0] != LINE_DONE;
3946 		*state = changed ? LINE_DECIDED : LINE_DONE;
3947 		if (lineno > 0) {
3948 			state[-1] = LINE_DONE;
3949 		}
3950 		if (!interlace_seen && lineno == (maxvpos + lof_store) * 2 - 2) {
3951 			state[1] = LINE_DONE;
3952 		}
3953 		break;
3954 	}
3955 }
3956 
3957 static void dummy_flush_line (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int line_no)
3958 {
3959 }
3960 
3961 static void dummy_flush_block (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int first_line, int last_line)
3962 {
3963 }
3964 
3965 static void dummy_flush_screen (struct vidbuf_description *gfxinfo, struct vidbuffer *vb, int first_line, int last_line)
3966 {
3967 }
3968 
3969 static void dummy_flush_clear_screen (struct vidbuf_description *gfxinfo, struct vidbuffer *vb)
3970 {
3971 }
3972 
3973 static int  dummy_lock (struct vidbuf_description *gfxinfo, struct vidbuffer *vb)
3974 {
3975 	return 1;
3976 }
3977 
3978 static void dummy_unlock (struct vidbuf_description *gfxinfo, struct vidbuffer *vb)
3979 {
3980 }
3981 
3982 static void gfxbuffer_reset (void)
3983 {
3984 	gfxvidinfo.drawbuffer.flush_line         = dummy_flush_line;
3985 	gfxvidinfo.drawbuffer.flush_block        = dummy_flush_block;
3986 	gfxvidinfo.drawbuffer.flush_screen       = dummy_flush_screen;
3987 	gfxvidinfo.drawbuffer.flush_clear_screen = dummy_flush_clear_screen;
3988 	gfxvidinfo.drawbuffer.lockscr            = dummy_lock;
3989 	gfxvidinfo.drawbuffer.unlockscr          = dummy_unlock;
3990 }
3991 
3992 void notice_resolution_seen (int res, bool lace)
3993 {
3994 	if (res > frame_res)
3995 		frame_res = res;
3996 	if (res > 0)
3997 		can_use_lores = 0;
3998 	if (!frame_res_lace && lace)
3999 		frame_res_lace = lace;
4000 }
4001 
4002 bool notice_interlace_seen (bool lace)
4003 {
4004 	bool changed = false;
4005 	// non-lace to lace switch (non-lace active at least one frame)?
4006 	if (lace) {
4007 		if (interlace_seen == 0) {
4008 			changed = true;
4009 			//write_log (_T("->lace PC=%x\n"), m68k_getpc ());
4010 		}
4011 		interlace_seen = currprefs.gfx_vresolution ? 1 : -1;
4012 	} else {
4013 		if (interlace_seen) {
4014 			changed = true;
4015 			//write_log (_T("->non-lace PC=%x\n"), m68k_getpc ());
4016 		}
4017 		interlace_seen = 0;
4018 	}
4019 	return changed;
4020 }
4021 
4022 void allocvidbuffer (struct vidbuffer *buf, int width, int height, int depth)
4023 {
4024 	memset (buf, 0, sizeof (struct vidbuffer));
4025 	buf->pixbytes = (depth + 7) / 8;
4026 	buf->width_allocated = (width + 7) & ~7;
4027 	buf->height_allocated = height;
4028 
4029 	buf->outwidth = buf->width_allocated;
4030 	buf->outheight = buf->height_allocated;
4031 	buf->inwidth = buf->width_allocated;
4032 	buf->inheight = buf->height_allocated;
4033 
4034 	int size = width * height * buf->pixbytes;
4035 	buf->realbufmem = xcalloc (uae_u8, size);
4036 	buf->bufmem_allocated = buf->bufmem = buf->realbufmem;
4037 	buf->rowbytes = width * buf->pixbytes;
4038 	buf->bufmemend = buf->realbufmem + size - buf->rowbytes;
4039 	buf->bufmem_lockable = true;
4040 }
4041 
4042 void freevidbuffer (struct vidbuffer *buf)
4043 {
4044 	xfree (buf->realbufmem);
4045 	memset (buf, 0, sizeof (struct vidbuffer));
4046 }
4047 
4048 void reset_drawing (void)
4049 {
4050 	max_diwstop = 0;
4051 
4052 	lores_reset ();
4053 
4054 	reset_decision_table();
4055 
4056 	init_aspect_maps ();
4057 
4058 	init_row_map ();
4059 
4060 	last_redraw_point = 0;
4061 
4062 	memset (spixels, 0, sizeof spixels);
4063 	memset (&spixstate, 0, sizeof spixstate);
4064 
4065 	init_drawing_frame ();
4066 	pfield_set_linetoscr();
4067 
4068 	notice_screen_contents_lost ();
4069 	frame_res_cnt = currprefs.gfx_autoresolution_delay;
4070 	lightpen_y1 = lightpen_y2 = -1;
4071 
4072 	reset_custom_limits ();
4073 
4074 	clearbuffer (&gfxvidinfo.drawbuffer);
4075 	clearbuffer (&gfxvidinfo.tempbuffer);
4076 
4077 	center_reset = true;
4078 	specialmonitoron = false;
4079 }
4080 
4081 void drawing_init (void)
4082 {
4083 	refresh_indicator_init();
4084 
4085 	gen_pfield_tables ();
4086 
4087 	uae_sem_init (&gui_sem, 0, 1);
4088 #ifdef PICASSO96
4089 	if (!isrestore ()) {
4090 		picasso_on = 0;
4091 		picasso_requested_on = 0;
4092 		gfx_set_picasso_state (0);
4093 	}
4094 #endif
4095 	xlinebuffer = gfxvidinfo.drawbuffer.bufmem;
4096 	xlinebuffer_genlock = NULL;
4097 
4098 	inhibit_frame = 0;
4099 
4100 	gfxbuffer_reset ();
4101 	reset_drawing ();
4102 }
4103 
4104 int isvsync_chipset (void)
4105 {
4106 	if (picasso_on || !currprefs.gfx_apmode[0].gfx_vsync || (currprefs.gfx_apmode[0].gfx_vsync == 0 && !currprefs.gfx_apmode[0].gfx_fullscreen))
4107 		return 0;
4108 	if (currprefs.gfx_apmode[0].gfx_vsyncmode == 0)
4109 		return 1;
4110 	if (currprefs.m68k_speed >= 0)
4111 		return -1;
4112 	return currprefs.cachesize ? -3 : -2;
4113 }
4114 
4115 int isvsync_rtg (void)
4116 {
4117 	if (!picasso_on || !currprefs.gfx_apmode[1].gfx_vsync || (currprefs.gfx_apmode[1].gfx_vsync == 0 && !currprefs.gfx_apmode[1].gfx_fullscreen))
4118 		return 0;
4119 	if (currprefs.gfx_apmode[1].gfx_vsyncmode == 0)
4120 		return 1;
4121 	if (currprefs.m68k_speed >= 0)
4122 		return -1;
4123 	return currprefs.cachesize ? -3 : -2;
4124 }
4125 
4126 int isvsync (void)
4127 {
4128 	if (picasso_on)
4129 		return isvsync_rtg ();
4130 	else
4131 		return isvsync_chipset ();
4132 }
4133