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