static int scanlinecount;
static int cia_hsync;
static bool toscr_scanline_complex_bplcon1;
+static bool spr_width_64_seen;
#define LOF_TOGGLES_NEEDED 3
//#define NLACE_CNT_NEEDED 50
int ptxhpos;
int ptxhpos2, ptxvpos2;
bool ignoreverticaluntilnextline;
+ int width;
+
+ uae_u16 ctl, pos;
+#ifdef AGA
+ uae_u16 data[4], datb[4];
+#else
+ uae_u16 data[1], datb[1];
+#endif
};
static struct sprite spr[MAX_SPRITES];
static int sprite_vblank_endline = VBLANK_SPRITE_PAL;
-static uae_u16 sprctl[MAX_SPRITES], sprpos[MAX_SPRITES];
-#ifdef AGA
-static uae_u16 sprdata[MAX_SPRITES][4], sprdatb[MAX_SPRITES][4];
-#else
-static uae_u16 sprdata[MAX_SPRITES][1], sprdatb[MAX_SPRITES][1];
-#endif
-static int sprite_last_drawn_at[MAX_SPRITES];
static int last_sprite_point, nr_armed;
static int sprite_width, sprres;
static int sprite_sprctlmask;
#endif
#ifdef AGA
|| line_decisions[next_lineno].bplcon4 != thisline_decision.bplcon4
+ || line_decisions[next_lineno].fmode != thisline_decision.fmode
#endif
)
#endif /* SMART_UPDATE */
static void record_sprite (int line, int num, int sprxp, uae_u16 *data, uae_u16 *datb, unsigned int ctl)
{
struct sprite_entry *e = curr_sprite_entries + next_sprite_entry;
- int i;
int word_offs;
uae_u32 collision_mask;
int width, dbl, half;
unsigned int mask = 0;
int attachment;
+ int spr_width;
half = 0;
dbl = sprite_buffer_res - sprres;
dbl = 0;
mask = 1 << half;
}
- width = (sprite_width << sprite_buffer_res) >> sprres;
- attachment = sprctl[num | 1] & 0x80;
+ spr_width = spr[num].width;
+ width = (spr_width << sprite_buffer_res) >> sprres;
+ attachment = spr[num | 1].ctl & 0x80;
/* Try to coalesce entries if they aren't too far apart */
- if (!next_sprite_forced && e[-1].max + sprite_width >= sprxp) {
+ /* Don't coelesce 64-bit wide sprites, needed to support FMODE change tricks */
+ if (!next_sprite_forced && e[-1].max + spr_width >= sprxp) {
e--;
} else {
next_sprite_entry++;
collision_mask = clxmask[clxcon >> 12];
word_offs = e->first_pixel + sprxp - e->pos;
- for (i = 0; i < sprite_width; i += 16) {
+ for (int i = 0; i < spr_width; i += 16) {
unsigned int da = *data;
unsigned int db = *datb;
uae_u32 datab = ((sprtaba[da & 0xFF] << 16) | sprtaba[da >> 8]
low order bit records whether the attach bit was set for this pair. */
if (attachment && !ecsshres ()) {
uae_u32 state = 0x01010101 << (num & ~1);
- uae_u8 *stb1 = spixstate.bytes + word_offs;
- for (i = 0; i < width; i += 8) {
+ uae_u8 *stb1 = spixstate.stb + word_offs;
+ for (int i = 0; i < width; i += 8) {
stb1[0] |= state;
stb1[1] |= state;
stb1[2] |= state;
}
e->has_attached = 1;
}
+ /* 64 pixel wide sprites' first 32 pixels work differently than
+ * last 32 pixels if FMODE is changed when sprite is being drawn
+ */
+ if (spr_width == 64) {
+ uae_u16 *stbfm = spixstate.stbfm + word_offs;
+ uae_u16 state = (3 << (2 * num));
+ for (int i = 0; i < width / 2; i += 8) {
+ stbfm[0] |= state;
+ stbfm[1] |= state;
+ stbfm[2] |= state;
+ stbfm[3] |= state;
+ stbfm[4] |= state;
+ stbfm[5] |= state;
+ stbfm[6] |= state;
+ stbfm[7] |= state;
+ stbfm += 8;
+ }
+ spr_width_64_seen = true;
+ }
}
static void add_sprite (int *countp, int num, int sprxp, int posns[], int nrs[])
int nrs[MAX_SPRITES * 2], posns[MAX_SPRITES * 2];
int count, i;
int point;
- int width = sprite_width;
int sscanmask = 0x100 << sprite_buffer_res;
int gotdata = 0;
int startnr = 0, endnr = MAX_SPRITES - 1;
count = 0;
for (i = startnr; i <= endnr; i++) {
+ struct sprite *s = &spr[i];
int xpos = spr[i].xpos;
int sprxp = (fmode & 0x8000) ? (xpos & ~sscanmask) : xpos;
int hw_xp = sprxp >> sprite_buffer_res;
- int pointx = usepointx && (sprctl[i] & sprite_sprctlmask) ? 0 : 1;
+ int pointx = usepointx && (s->ctl & sprite_sprctlmask) ? 0 : 1;
if (xpos < 0)
continue;
for (i = 0; i < count; i++) {
int nr = nrs[i] & (MAX_SPRITES - 1);
- record_sprite (next_lineno, nr, posns[i], sprdata[nr], sprdatb[nr], sprctl[nr]);
+ struct sprite *s = &spr[nr];
+ record_sprite (next_lineno, nr, posns[i], s->data, s->datb, s->ctl);
/* get left and right sprite edge if brdsprt enabled */
#if AUTOSCALE_SPRITES
if (dmaen (DMA_SPRITE) && (bplcon0 & 1) && (bplcon3 & 0x02) && !(bplcon3 & 0x20) && nr > 0) {
int j, jj;
for (j = 0, jj = 0; j < sprite_width; j+= 16, jj++) {
int nx = fromspritexdiw (posns[i] + j);
- if (sprdata[nr][jj] || sprdatb[nr][jj]) {
+ if (s->data[jj] || s->datb[jj]) {
if (diwfirstword_total > nx && nx >= (48 << currprefs.gfx_resolution))
diwfirstword_total = nx;
if (diwlastword_total < nx + 16 && nx <= (448 << currprefs.gfx_resolution))
}
static void maybe_decide_sprites(int spnr, int hpos)
{
- if (!spr[spnr].armed)
+ struct sprite *s = &spr[spnr];
+ if (!s->armed)
return;
- if (!sprdata[spnr] && !sprdatb[spnr])
+ if (!s->data && !s->datb)
return;
decide_sprites(spnr, hpos, true, true);
}
if (memcmp (spixels + this_first->first_pixel, spixels + prev_first->first_pixel,
npixels * sizeof (uae_u16)) != 0)
return 1;
- if (memcmp (spixstate.bytes + this_first->first_pixel, spixstate.bytes + prev_first->first_pixel, npixels) != 0)
+ if (memcmp (spixstate.stb + this_first->first_pixel, spixstate.stb + prev_first->first_pixel, npixels) != 0)
return 1;
return 0;
}
#endif
#ifdef AGA
thisline_decision.bplcon4 = bplcon4;
+ thisline_decision.fmode = fmode;
#endif
bplcon0d_old = -1;
toscr_res_old = -1;
fmode_saved = v;
set_chipset_mode();
bpldmainitdelay (hpos);
+ record_register_change(hpos, 0x1fc, fmode);
}
static void FNULL (uae_u16 v)
struct sprite *s = &spr[num];
sprstartstop (s);
- sprxp = (sprpos[num] & 0xFF) * 2 + (sprctl[num] & 1);
+ sprxp = (s->pos & 0xFF) * 2 + (s->ctl & 1);
sprxp <<= sprite_buffer_res;
/* Quite a bit salad in this register... */
if (0) {
}
#ifdef AGA
else if (currprefs.chipset_mask & CSMASK_AGA) {
- sprxp |= ((sprctl[num] >> 3) & 3) >> (RES_MAX - sprite_buffer_res);
- s->dblscan = sprpos[num] & 0x80;
+ sprxp |= ((s->ctl >> 3) & 3) >> (RES_MAX - sprite_buffer_res);
+ s->dblscan = s->pos & 0x80;
}
#endif
#ifdef ECS_DENISE
else if (currprefs.chipset_mask & CSMASK_ECS_DENISE) {
- sprxp |= ((sprctl[num] >> 3) & 2) >> (RES_MAX - sprite_buffer_res);
+ sprxp |= ((s->ctl >> 3) & 2) >> (RES_MAX - sprite_buffer_res);
}
#endif
s->xpos = sprxp;
- s->vstart = sprpos[num] >> 8;
- s->vstart |= (sprctl[num] & 0x04) ? 0x0100 : 0;
- s->vstop = sprctl[num] >> 8;
- s->vstop |= (sprctl[num] & 0x02) ? 0x100 : 0;
+ s->vstart = s->pos >> 8;
+ s->vstart |= (s->ctl & 0x04) ? 0x0100 : 0;
+ s->vstop = s->ctl >> 8;
+ s->vstop |= (s->ctl & 0x02) ? 0x100 : 0;
if (currprefs.chipset_mask & CSMASK_ECS_AGNUS) {
- s->vstart |= (sprctl[num] & 0x40) ? 0x0200 : 0;
- s->vstop |= (sprctl[num] & 0x20) ? 0x0200 : 0;
+ s->vstart |= (s->ctl & 0x40) ? 0x0200 : 0;
+ s->vstop |= (s->ctl & 0x20) ? 0x0200 : 0;
}
sprstartstop (s);
}
static void SPRxCTL_1(uae_u16 v, int num, int hpos)
{
- if (hpos >= maxhpos - 2 && sprctl[num] != v && vpos < maxvpos - 1) {
- struct sprite *s = &spr[num];
+ struct sprite *s = &spr[num];
+ if (hpos >= maxhpos - 2 && s->ctl != v && vpos < maxvpos - 1) {
vpos++;
sprstartstop(s);
vpos--;
s->ignoreverticaluntilnextline = true;
sprite_ignoreverticaluntilnextline = true;
}
- sprctl[num] = v;
+ s->ctl = v;
spr_arm (num, 0);
SPRxCTLPOS (num);
}
static void SPRxPOS_1(uae_u16 v, int num, int hpos)
{
- if (hpos >= maxhpos - 2 && sprpos[num] != v && vpos < maxvpos - 1) {
- struct sprite *s = &spr[num];
+ struct sprite *s = &spr[num];
+ if (hpos >= maxhpos - 2 && s->pos != v && vpos < maxvpos - 1) {
vpos++;
sprstartstop(s);
vpos--;
s->ignoreverticaluntilnextline = true;
sprite_ignoreverticaluntilnextline = true;
}
- sprpos[num] = v;
+ s->pos = v;
SPRxCTLPOS (num);
#if SPRITE_DEBUG > 0
- struct sprite *s = &spr[num];
if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY && (SPRITE_DEBUG & (1 << num))) {
write_log (_T("%d:%d:SPR%dPOS %04X P=%06X VSTRT=%d VSTOP=%d HSTRT=%d D=%d A=%d CP=%x PC=%x\n"),
vpos, hpos, num, v, s->pt, s->vstart, s->vstop, s->xpos, spr[num].dmastate, spr[num].armed, cop_state.ip, M68K_GETPC);
}
static void SPRxDATA_1(uae_u16 v, int num, int hpos)
{
- sprdata[num][0] = v;
+ struct sprite *s = &spr[num];
+ s->data[0] = v;
#ifdef AGA
- sprdata[num][1] = v;
- sprdata[num][2] = v;
- sprdata[num][3] = v;
+ s->data[1] = v;
+ s->data[2] = v;
+ s->data[3] = v;
+ s->width = sprite_width;
#endif
spr_arm (num, 1);
#if SPRITE_DEBUG >= 256
}
static void SPRxDATB_1(uae_u16 v, int num, int hpos)
{
- sprdatb[num][0] = v;
+ struct sprite *s = &spr[num];
+ s->datb[0] = v;
#ifdef AGA
- sprdatb[num][1] = v;
- sprdatb[num][2] = v;
- sprdatb[num][3] = v;
+ s->datb[1] = v;
+ s->datb[2] = v;
+ s->datb[3] = v;
+ s->width = sprite_width;
#endif
#if SPRITE_DEBUG >= 256
if (vpos >= SPRITE_DEBUG_MINY && vpos <= SPRITE_DEBUG_MAXY && (SPRITE_DEBUG & (1 << num))) {
{
case 64:
if (cycle == 0) {
- sprdata[num][1] = data321;
- sprdata[num][2] = data322 >> 16;
- sprdata[num][3] = data322;
+ s->data[1] = data321;
+ s->data[2] = data322 >> 16;
+ s->data[3] = data322;
} else {
- sprdatb[num][1] = data321;
- sprdatb[num][2] = data322 >> 16;
- sprdatb[num][3] = data322;
+ s->datb[1] = data321;
+ s->datb[2] = data322 >> 16;
+ s->datb[3] = data322;
}
break;
case 32:
- if (cycle == 0)
- sprdata[num][1] = data321;
- else
- sprdatb[num][1] = data321;
+ if (cycle == 0) {
+ s->data[1] = data321;
+ s->data[2] = data;
+ s->data[3] = data321;
+ } else {
+ s->datb[1] = data321;
+ s->datb[2] = data;
+ s->datb[3] = data321;
+ }
break;
}
#endif
static void init_sprites (void)
{
- memset (sprpos, 0, sizeof sprpos);
- memset (sprctl, 0, sizeof sprctl);
+ for (int i = 0; i < MAX_SPRITES; i++) {
+ struct sprite *s = &spr[i];
+ s->pos = 0;
+ s->ctl = 0;
+ }
}
static void init_hardware_frame (void)
int first_pixel = prev_sprite_entries[0].first_pixel;
int npixels = prev_sprite_entries[prev_next_sprite_entry].first_pixel - first_pixel;
memset (spixels + first_pixel, 0, npixels * sizeof *spixels);
- memset (spixstate.bytes + first_pixel, 0, npixels * sizeof *spixstate.bytes);
+ memset(spixstate.stb + first_pixel, 0, npixels * sizeof *spixstate.stb);
+ if (spr_width_64_seen) {
+ memset(spixstate.stbfm + first_pixel, 0, npixels * sizeof *spixstate.stbfm);
+ spr_width_64_seen = false;
+ }
}
prev_next_sprite_entry = next_sprite_entry;
CLXCON2 (0);
setup_fmodes (0);
sprite_width = GET_SPRITEWIDTH (fmode);
+ for (int i = 0; i < MAX_SPRITES; i++) {
+ spr[i].width = sprite_width;
+ }
beamcon0 = new_beamcon0 = currprefs.ntscmode ? 0x00 : 0x20;
bltstate = BLT_done;
blit_interrupt = 1;
SL (spr[i].pt); /* 120-13E SPRxPT */
}
for (i = 0; i < 8; i++) {
- SW (sprpos[i]); /* 1x0 SPRxPOS */
- SW (sprctl[i]); /* 1x2 SPRxPOS */
- SW (sprdata[i][0]); /* 1x4 SPRxDATA */
- SW (sprdatb[i][0]); /* 1x6 SPRxDATB */
+ struct sprite *s = &spr[i];
+ SW (s->pos); /* 1x0 SPRxPOS */
+ SW (s->ctl); /* 1x2 SPRxPOS */
+ SW (s->data[0]); /* 1x4 SPRxDATA */
+ SW (s->datb[0]); /* 1x6 SPRxDATB */
}
}
for (i = 0; i < 32; i++) {
uae_u8 *restore_custom_sprite (int num, uae_u8 *src)
{
- memset (&spr[num], 0, sizeof (struct sprite));
- spr[num].pt = RL; /* 120-13E SPRxPT */
- sprpos[num] = RW; /* 1x0 SPRxPOS */
- sprctl[num] = RW; /* 1x2 SPRxPOS */
- sprdata[num][0] = RW; /* 1x4 SPRxDATA */
- sprdatb[num][0] = RW; /* 1x6 SPRxDATB */
- sprdata[num][1] = RW;
- sprdatb[num][1] = RW;
- sprdata[num][2] = RW;
- sprdatb[num][2] = RW;
- sprdata[num][3] = RW;
- sprdatb[num][3] = RW;
- spr[num].armed = RB & 1;
+ struct sprite *s = &spr[num];
+ memset (s, 0, sizeof (struct sprite));
+ s->pt = RL; /* 120-13E SPRxPT */
+ s->pos = RW; /* 1x0 SPRxPOS */
+ s->ctl = RW; /* 1x2 SPRxPOS */
+ s->data[0] = RW; /* 1x4 SPRxDATA */
+ s->datb[0] = RW; /* 1x6 SPRxDATB */
+ s->data[1] = RW;
+ s->datb[1] = RW;
+ s->data[2] = RW;
+ s->datb[2] = RW;
+ s->data[3] = RW;
+ s->datb[3] = RW;
+ s->armed = RB & 1;
return src;
}
uae_u8 *save_custom_sprite (int num, int *len, uae_u8 *dstptr)
{
uae_u8 *dstbak, *dst;
+ struct sprite *s = &spr[num];
if (dstptr)
dstbak = dst = dstptr;
else
dstbak = dst = xmalloc (uae_u8, 30);
- SL (spr[num].pt); /* 120-13E SPRxPT */
- SW (sprpos[num]); /* 1x0 SPRxPOS */
- SW (sprctl[num]); /* 1x2 SPRxPOS */
- SW (sprdata[num][0]); /* 1x4 SPRxDATA */
- SW (sprdatb[num][0]); /* 1x6 SPRxDATB */
- SW (sprdata[num][1]);
- SW (sprdatb[num][1]);
- SW (sprdata[num][2]);
- SW (sprdatb[num][2]);
- SW (sprdata[num][3]);
- SW (sprdatb[num][3]);
- SB (spr[num].armed ? 1 : 0);
+ SL (s->pt); /* 120-13E SPRxPT */
+ SW (s->pos); /* 1x0 SPRxPOS */
+ SW (s->ctl); /* 1x2 SPRxPOS */
+ SW (s->data[0]); /* 1x4 SPRxDATA */
+ SW (s->datb[0]); /* 1x6 SPRxDATB */
+ SW (s->data[1]);
+ SW (s->datb[1]);
+ SW (s->data[2]);
+ SW (s->datb[2]);
+ SW (s->data[3]);
+ SW (s->datb[3]);
+ SB (s->armed ? 1 : 0);
*len = dst - dstbak;
return dstbak;
}
xcolnr xcolors[4096];
struct spritepixelsbuf {
- uae_u8 attach;
+ bool attach;
uae_u8 stdata;
+ uae_u16 stfmdata;
uae_u16 data;
};
static struct spritepixelsbuf spritepixels_buffer[MAX_PIXELS_PER_LINE];
uae_u16 spixels[2 * MAX_SPR_PIXELS];
#endif
-/* Eight bits for every pixel. */
-union sps_union spixstate;
+struct sprite_stb spixstate;
static uae_u32 ham_linebuf[MAX_PIXELS_PER_LINE * 2];
static uae_u8 *real_bplpt[8];
static uae_u8 ecs_genlock_features_mask;
static bool ecs_genlock_features_colorkey;
static int hsync_shift_hack;
+static bool sprite_smaller_than_64;
uae_sem_t gui_sem;
int *shift_lookup = dualpf ? (bpldualpfpri ? dblpf_ms2 : dblpf_ms1) : dblpf_ms;
int maskshift, plfmask;
+ // If 64 pixel wide sprite and FMODE gets lowered when sprite's
+ // first 32 pixels are being drawn: matching pixel(s) in second
+ // 32 pixel part gets blanked.
+ if (aga && spb->stfmdata && sprite_smaller_than_64) {
+ spb[32 << currprefs.gfx_resolution].data &= ~spb->stfmdata;
+ }
+
// shdelay hack, above &spritepixels[pos] is correct.
pos += sprite_shdelay;
/* The value in the shift lookup table is _half_ the shift count we
STATIC_INLINE void draw_sprites_1 (struct sprite_entry *e, int dualpf, int has_attach)
{
uae_u16 *buf = spixels + e->first_pixel;
- uae_u8 *stbuf = spixstate.bytes + e->first_pixel;
+ uae_u8 *stbuf = spixstate.stb + e->first_pixel;
+ uae_u16 *stfmbuf = spixstate.stbfm + e->first_pixel;
int spr_pos, pos;
int epos = e->pos;
int emax = e->max;
buf -= epos;
stbuf -= epos;
+ stfmbuf -= epos;
spr_pos = epos + ((DIW_DDF_OFFSET - DISPLAY_LEFT_SHIFT) << sprite_buffer_res);
if (spr_pos >= 0 && spr_pos < MAX_PIXELS_PER_LINE) {
spritepixels[spr_pos].data = buf[pos];
spritepixels[spr_pos].stdata = stbuf[pos];
+ spritepixels[spr_pos].stfmdata = stfmbuf[pos];
spritepixels[spr_pos].attach = has_attach;
}
}
bpldelay_sh = sh;
pfield_mode_changed = true;
}
+ sprite_smaller_than_64 = (dp_for_drawing->fmode & 0x0c) != 0x0c;
#endif
ecs_genlock_features_active = (currprefs.chipset_mask & CSMASK_ECS_DENISE) && ((dp_for_drawing->bplcon2 & 0x0c00) || ce_is_borderntrans(colors_for_drawing.extra)) ? 1 : 0;
if (ecs_genlock_features_active) {
case 0x10c: // BPLCON4
dp_for_drawing->bplcon4 = v;
break;
+ case 0x1fc: // FMODE
+ dp_for_drawing->fmode = v;
+ break;
#endif
}
pfield_expand_dp_bplcon ();
uae_u16 b2 = dp_for_drawing->bplcon2;
uae_u16 b3 = dp_for_drawing->bplcon3;
uae_u16 b4 = dp_for_drawing->bplcon4;
+ uae_u16 fm = dp_for_drawing->fmode;
init_ham_decoding ();
do_color_changes (dummy_worker, decode_ham, lineno);
if (have_color_changes) {
dp_for_drawing->bplcon2 = b2;
dp_for_drawing->bplcon3 = b3;
dp_for_drawing->bplcon4 = b4;
+ dp_for_drawing->fmode = fm;
pfield_expand_dp_bplcon ();
}
hposblank = ohposblank;