From aa80be67bc01d1ff673e39da2ac420cde9926672 Mon Sep 17 00:00:00 2001 From: kub Date: Thu, 8 Aug 2024 22:33:42 +0200 Subject: [PATCH] core vdp, some restructuring --- pico/draw.c | 897 ++++++++++++++++++---------------------------------- 1 file changed, 300 insertions(+), 597 deletions(-) diff --git a/pico/draw.c b/pico/draw.c index 6d27f1b7d..12d0d935d 100644 --- a/pico/draw.c +++ b/pico/draw.c @@ -85,8 +85,8 @@ u32 VdpSATCache[2*128]; // VDP sprite cache (1st 32 sprite attr bits) #define LF_PLANE (1 << 0) // must be = 1 #define LF_SH (1 << 1) // must be = 2 //#define LF_FORCE (1 << 2) -#define LF_LINE (1 << 3) // covers the line -#define LF_LPRIO (1 << 8) // seen low prio tile +#define LF_LINE (1 << 3) // layer covers line +#define LF_LPRIO (1 << 8) // line has low prio tiles #define LF_PLANE_A 0 #define LF_PLANE_B 1 @@ -284,7 +284,6 @@ TileFlipMakerAS(TileFlipAS_onlymark, pix_sh_as_onlymark) // NB s/h already resolved by non-forced drawing // forced both layer draw (through debug reg) #define pix_and(x) \ - pal |= 0xc0; /* leave s/h bits untouched in pixel "and" */ \ pd[x] &= pal|t TileNormMaker(TileNorm_and, pix_and) @@ -292,7 +291,6 @@ TileFlipMaker(TileFlip_and, pix_and) // forced sprite draw (through debug reg) #define pix_sh_as_and(x) \ - pal |= 0xc0; /* leave s/h bits untouched in pixel "and" */ \ if (likely(m & (1<<(x+8)))) { \ m &= ~(1<<(x+8)); \ /* if (!t) pd[x] |= 0x40; as per titan hw notes? */ \ @@ -305,33 +303,30 @@ TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and) // -------------------------------------------- -#ifndef _ASM_DRAW_C -#define DrawTile(mask,masked) { \ +#define DrawTile(mask,yshift,ymask,hpcode,cache) { \ if (code!=oldcode) { \ oldcode = code; \ \ pack = 0; \ if (code != blank) { \ /* Get tile address/2: */ \ - u32 addr = ((code&0x7ff)<<4) + ty; \ - if (code & 0x1000) addr ^= 0xe; /* Y-flip */ \ + u32 addr = ((code<>9)&0x30) | sh; /* shadow */ \ - \ pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); \ if (!pack) \ blank = code; \ } \ } \ - \ - if (code & 0x8000) { /* (un-forced) high priority tile */ \ + if (cache && (code & 0x8000)) { /* (un-forced) high priority tile */ \ if (sh | (pack&mask)) { \ - code |= (dx<<16) | (ty<<26) | (masked<<25); \ - if (code & 0x1000) code ^= 0xe<<26; \ - *hc++ = code, *hc++ = pack&mask; /* cache it */ \ + code = hpcode | (dx<<16); \ + if (code & 0x1000) code ^= ymask<<(26+1); /* Y-flip */ \ + *hc++ = code; *hc++ = pack&mask; /* cache it */ \ } \ } else { \ - lflags |= LF_LPRIO; \ + if (cache) lflags |= LF_LPRIO; \ if (pack&mask) { \ if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal); \ else TileNorm(pd + dx, pack&mask, pal); \ @@ -339,355 +334,261 @@ TileFlipMakerAS(TileFlipSH_AS_and, pix_sh_as_and) } \ } -static void DrawStrip(struct TileStrip *ts, int lflags, int cellskip) -{ - unsigned char *pd = Pico.est.HighCol; - u32 *hc = ts->hc; - int tilex, dx, ty, cells; - u32 code, oldcode = -1, blank = -1; // The tile we know is blank - u32 pal = 0, pack = 0, sh, mask; - - // Draw tiles across screen: - sh = (lflags & LF_SH) << 6; // shadow - tilex=((-ts->hscroll)>>3)+cellskip; - ty=(ts->line&7)<<1; // Y-Offset into tile - dx=((ts->hscroll-1)&7)+1; - cells = ts->cells - cellskip; - dx+=cellskip<<3; - - if (dx & 7) { - code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; -// code &= ~force; // forced always draw everything - - mask = 0xffffffff<<((dx&7)*4); - if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); - mask = (~mask << 16) | (~mask >> 16); - - DrawTile(mask,1); - dx += 8, tilex++, cells--; - } - -// int force = (lflags&LF_FORCE) << 13; - for (; cells > 0; dx+=8, tilex++, cells--) - { - code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; -// code &= ~force; // forced always draw everything - - if (code != blank || ((code & 0x8000) && sh)) - DrawTile(~0,0); - } - - if (dx & 7) { - code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; -// code &= ~force; // forced always draw everything - - if (code != blank || ((code & 0x8000) && sh)) { - mask = 0xffffffff<<((dx&7)*4); - if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); - mask = (mask << 16) | (mask >> 16); - - DrawTile(mask,1); - } - } - - // terminate the cache list - *hc = 0; - - // flags bit is clear if all layer is hi priority - if (!(lflags & LF_LPRIO) && (lflags & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO; -} - -#define DrawTileVSRam(mask,masked) { \ - if (code!=oldcode) { \ - oldcode = code; \ - /* Get tile address/2: */ \ - addr = (code&0x7ff)<<4; \ +#define DrawStripMaker(funcname,yshift,ymask,hpcode,drawtile,cache) \ +void funcname(struct TileStrip *ts, int lflags, int cellskip) \ +{ \ + unsigned char *pd = Pico.est.HighCol; \ + u32 *hc = ts->hc; \ + int tilex, dx, ty, cells; \ + u32 code, oldcode = -1, blank = -1; /* The tile we know is blank */ \ + u32 pal = 0, pack = 0, sh, mask = ~0; \ + \ + /* Draw tiles across screen: */ \ + sh = (lflags & LF_SH) << 6; /* shadow */ \ + tilex=((-ts->hscroll)>>3)+cellskip; \ + ty=(ts->line&ymask)<<1; /* Y-Offset into tile */ \ + dx=((ts->hscroll-1)&7)+1; \ + cells = ts->cells - cellskip; \ + dx+=cellskip<<3; \ \ - pal = ((code>>9)&0x30) | sh; /* shadow */ \ +/* int force = (plane_sh&LF_FORCE) << 13; */ \ + if (dx & 7) { \ + code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; \ +/* code &= ~force; *//* forced always draw everything */ \ \ - pack = (code & 0x1000 ? ty^0xe : ty); /* Y-flip */ \ - pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr+pack)); \ - if (!pack) \ - blank = code; \ + mask = 0xffffffff<<((dx&7)*4); \ + if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); \ + mask = (~mask << 16) | (~mask >> 16); \ + \ + drawtile(mask,yshift,ymask,hpcode | (ty<<26) | (1<<25),cache); \ + dx += 8, tilex++, cells--; \ } \ \ - if (code & 0x8000) { /* (un-forced) high priority tile */ \ - if (sh | (pack&mask)) { \ - code |= (dx<<16) | (masked<<25); \ - if (code & 0x1000) code ^= 0xe<<26; \ - *hc++ = code, *hc++ = pack&mask; /* cache it */ \ - } \ - } else { \ - plane_sh |= LF_LPRIO; \ - if (pack&mask) { \ - if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal); \ - else TileNorm(pd + dx, pack&mask, pal); \ + for (; cells > 0; dx+=8, tilex++, cells--) \ + { \ + code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; \ +/* code &= ~force; *//* forced always draw everything */ \ + \ + if (code != blank || ((code & 0x8000) && sh)) \ + drawtile(~0,yshift,ymask,hpcode | (ty<<26),cache); \ + } \ + \ + if (dx & 7) { \ + code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; \ +/* code &= ~force; *//* forced always draw everything */ \ + \ + if (code != blank || ((code & 0x8000) && sh)) { \ + mask = 0xffffffff<<((dx&7)*4); \ + if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); \ + mask = (mask << 16) | (mask >> 16); \ + \ + drawtile(mask,yshift,ymask,hpcode | (ty<<26) | (1<<25),cache); \ } \ } \ + \ + /* terminate the cache list */ \ + if (cache) *hc = 0; \ + \ + /* if oldcode wasn't changed, it means all layer is hi priority */ \ + if (cache && (lflags & (LF_LINE|LF_LPRIO)) == LF_LINE) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO; \ } -// this is messy -static void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip) -{ - unsigned char *pd = Pico.est.HighCol; - u32 *hc = ts->hc; - int tilex, dx, ty = 0, addr = 0, cell = 0, nametabadd = 0; - u32 code, oldcode = -1, blank = -1; // The tile we know is blank - u32 pal = 0, pack, scan = Pico.est.DrawScanline, sh, plane, mask; - - // Draw tiles across screen: - sh = (plane_sh & LF_SH) << 6; // shadow - plane = (plane_sh & LF_PLANE); // plane to draw - tilex=(-ts->hscroll)>>3; - dx=((ts->hscroll-1)&7)+1; - if (ts->hscroll & 0x0f) { - int adj = ((ts->hscroll ^ dx) >> 3) & 1; - cell -= adj + 1; - ts->cells -= adj; - PicoMem.vsram[0x3e] = PicoMem.vsram[0x3f] = plane_sh >> 16; - } - cell+=cellskip; - tilex+=cellskip; - dx+=cellskip<<3; - -// int force = (plane_sh&LF_FORCE) << 13; - if ((cell&1)==1 || (dx&7)) { - int line,vscroll; - vscroll = PicoMem.vsram[plane + (cell&0x3e)]; - - // Find the line in the name table - line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. - nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] - ty=(line&7)<<1; // Y-Offset into tile - } - if (dx & 7) { - code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; - code |= ty<<26; // add ty since that can change pixel row for every 2nd tile -// code &= ~force; // forced always draw everything - - mask = 0xffffffff<<((dx&7)*4); - if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); - mask = (~mask << 16) | (~mask >> 16); - - DrawTileVSRam(mask,1); - - dx += 8, tilex++, cell++; - } - for (; cell < ts->cells; dx+=8,tilex++,cell++) - { - if ((cell&1)==0) { - int line,vscroll; - vscroll = PicoMem.vsram[plane + (cell&0x3e)]; - - // Find the line in the name table - line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. - nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] - ty=(line&7)<<1; // Y-Offset into tile - } - - code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; - code |= ty<<26; // add ty since that can change pixel row for every 2nd tile -// code &= ~force; // forced always draw everything - - if (code != blank || ((code & 0x8000) && sh)) - DrawTileVSRam(~0,0); - } - if (dx & 7) { - if ((cell&1)==0) { - int line,vscroll; - vscroll = PicoMem.vsram[plane + (cell&0x3e)]; - - // Find the line in the name table - line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. - nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] - ty=(line&7)<<1; // Y-Offset into tile - } - - code= PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; - code |= ty<<26; // add ty since that can change pixel row for every 2nd tile -// code &= ~force; // forced always draw everything - - if (code != blank || ((code & 0x8000) && sh)) { - mask = 0xffffffff<<((dx&7)*4); - if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); - mask = (mask << 16) | (mask >> 16); - - DrawTileVSRam(mask,1); - } - } - - // terminate the cache list - *hc = 0; +#ifndef _ASM_DRAW_C +static DrawStripMaker(DrawStrip, 4, 0x7, code, DrawTile, 1); - if (!(plane_sh & LF_LPRIO) && (plane_sh & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO; -} +static #endif + DrawStripMaker(DrawStripInterlace, 5, 0xf, (code&0xfc00) | ((code&0x3ff)<<1), DrawTile, 1); -#define DrawTileInterlace(mask,masked) { \ - if (code!=oldcode) { \ - oldcode = code; \ +// this is messy +#define DrawStripVSRamMaker(funcname,yshift,ymask,hpcode,drawtile,cache) \ +void funcname(struct TileStrip *ts, int lflags, int cellskip) \ +{ \ + unsigned char *pd = Pico.est.HighCol; \ + u32 *hc = ts->hc; \ + int tilex, dx, ty = 0, cell = 0, nametabadd = 0; \ + u32 code, oldcode = -1, blank = -1; /* The tile we know is blank */ \ + u32 pal = 0, pack = 0, sh, plane, mask; \ + int scan = Pico.est.DrawScanline<<(yshift-4); \ \ - pack = 0; \ - if (code != blank) { \ - /* Get tile address/2: */ \ - u32 addr = ((code&0x3ff)<<5) + ty; \ - if (code & 0x1000) addr ^= 0x1e; /* Y-flip */ \ + /* Draw tiles across screen: */ \ + sh = (lflags & LF_SH) << 6; /* shadow */ \ + plane = (lflags & LF_PLANE); /* plane to draw */ \ + tilex=(-ts->hscroll)>>3; \ + dx=((ts->hscroll-1)&7)+1; \ + if (ts->hscroll & 0x0f) { \ + int adj = ((ts->hscroll ^ dx) >> 3) & 1; \ + cell -= adj + 1; \ + ts->cells -= adj; \ + PicoMem.vsram[0x3e] = PicoMem.vsram[0x3f] = lflags >> 16; \ + } \ + cell+=cellskip; \ + tilex+=cellskip; \ + dx+=cellskip<<3; \ \ - pal = ((code>>9)&0x30) | sh; /* shadow */ \ +/* int force = (lflags&LF_FORCE) << 13; */ \ + if ((cell&1)==1 || (dx&7)) { \ + int line,vscroll; \ + vscroll = PicoMem.vsram[plane + (cell&0x3e)]; \ \ - pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); \ - if (!pack) \ - blank = code; \ + /* Find the line in the name table */ \ + line=(vscroll+scan)&(u16)ts->line; /* ts->line is really ymask, */ \ + nametabadd=(line>>(yshift-1))<<(ts->line>>24); /* and shift[width] */ \ + ty=((line<<(yshift-4))&ymask)<<1; /* Y-Offset into tile */ \ + } \ + if (dx & 7) { \ + code = PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; \ + code |= ty<<26; /* add ty since that can change pixel row for every 2nd tile */ \ +/* code &= ~force; *//* forced always draw everything */ \ + \ + mask = 0xffffffff<<((dx&7)*4); \ + if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); \ + mask = (~mask << 16) | (~mask >> 16); \ + \ + drawtile(mask,yshift,ymask,hpcode | (1<<25),cache); \ + \ + dx += 8, tilex++, cell++; \ + } \ + for (; cell < ts->cells; dx+=8,tilex++,cell++) \ + { \ + if ((cell&1)==0) \ + { \ + int line,vscroll; \ + vscroll = PicoMem.vsram[plane + (cell&0x3e)]; \ + \ + /* Find the line in the name table */ \ + line=(vscroll+scan)&(u16)ts->line; /* ts->line is really ymask, */ \ + nametabadd=(line>>(yshift-1))<<(ts->line>>24); /* and shift[width] */ \ + ty=((line<<(yshift-4))&ymask)<<1; /* Y-Offset into tile */ \ } \ + \ + code = PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; \ + code |= ty<<26; /* add ty since that can change pixel row for every 2nd tile */ \ +/* code &= ~force; *//* forced always draw everything */ \ + \ + if (code != blank || ((code & 0x8000) && sh)) \ + drawtile(~0,yshift,ymask,hpcode,cache); \ } \ + if (dx & 7) { \ + if ((cell&1)==0) \ + { \ + int line,vscroll; \ + vscroll = PicoMem.vsram[plane + (cell&0x3e)]; \ \ - if (code & 0x8000) { /* high priority tile */ \ - if (sh | (pack&mask)) { \ - code = (code&0xfc00) | ((code&0x3ff)<<1) | (dx<<16) | (ty<<26) | (masked<<25); \ - if (code & 0x1000) code ^= 0x1e<<26; \ - *hc++ = code, *hc++ = pack&mask; /* cache it */ \ + /* Find the line in the name table */ \ + line=(vscroll+scan)&(u16)ts->line; /* ts->line is really ymask, */ \ + nametabadd=(line>>(yshift-1))<<(ts->line>>24); /* and shift[width] */ \ + ty=((line<<(yshift-4))&ymask)<<1; /* Y-Offset into tile */ \ } \ - } else { \ - plane_sh |= LF_LPRIO; \ - if (pack&mask) { \ - if (code & 0x0800) TileFlip(pd + dx, pack&mask, pal); \ - else TileNorm(pd + dx, pack&mask, pal); \ + \ + code = PicoMem.vram[ts->nametab + nametabadd + (tilex & ts->xmask)]; \ + code |= ty<<26; /* add ty since that can change pixel row for every 2nd tile */ \ +/* code &= ~force; *//* forced always draw everything */ \ + \ + if (code != blank || ((code & 0x8000) && sh)) { \ + mask = 0xffffffff<<((dx&7)*4); \ + if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); \ + mask = (mask << 16) | (mask >> 16); \ + \ + drawtile(mask,yshift,ymask,hpcode | (1<<25),cache); \ } \ } \ + \ + /* terminate the cache list */ \ + if (cache) *hc = 0; \ + \ + if (cache && (lflags & (LF_LINE|LF_LPRIO)) == LF_LINE) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO; \ } #ifndef _ASM_DRAW_C +static DrawStripVSRamMaker(DrawStripVSRam, 4, 0x7, code, DrawTile, 1); + static #endif -void DrawStripInterlace(struct TileStrip *ts, int plane_sh) -{ - unsigned char *pd = Pico.est.HighCol; - u32 *hc = ts->hc; - int tilex = 0, dx = 0, ty = 0, cells; - u32 code, oldcode = -1, blank = -1; // The tile we know is blank - u32 pal = 0, pack = 0, sh, mask; - - // Draw tiles across screen: - sh = (plane_sh & LF_SH) << 6; // shadow - tilex=(-ts->hscroll)>>3; - ty=(ts->line&15)<<1; // Y-Offset into tile - dx=((ts->hscroll-1)&7)+1; - cells = ts->cells; - - if (dx & 7) { - code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; -// code &= ~force; // forced always draw everything - - mask = 0xffffffff<<(dx*4); - if (code & 0x0800) mask = 0xffffffff>>(dx*4); - mask = (~mask << 16) | (~mask >> 16); - - DrawTileInterlace(mask,1); - dx += 8, tilex++, cells--; - } - -// int force = (plane_sh&LF_FORCE) << 13; - for (; cells; dx+=8,tilex++,cells--) - { - u32 code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; -// code &= ~force; // forced always draw everything - - if (code != blank || ((code & 0x8000) && sh)) - DrawTileInterlace(~0,0); - } - - if (dx & 7) { - code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; -// code &= ~force; // forced always draw everything - - if (code != blank || ((code & 0x8000) && sh)) { - mask = 0xffffffff<<((dx&7)*4); - if (code & 0x0800) mask = 0xffffffff>>((dx&7)*4); - mask = (mask << 16) | (mask >> 16); - - DrawTileInterlace(mask,1); - } - } - - // terminate the cache list - *hc = 0; - - if (!(plane_sh & LF_LPRIO) && (plane_sh & LF_LINE)) Pico.est.rendstatus |= PDRAW_PLANE_HI_PRIO; -} + DrawStripVSRamMaker(DrawStripVSRamInterlace, 5, 0xf, (code&0xfc00) | ((code&0x3ff)<<1), DrawTile, 1); // -------------------------------------------- -#ifndef _ASM_DRAW_C -static void DrawLayer(int plane_sh, u32 *hcache, int cellskip, int maxcells, - struct PicoEState *est) -{ - struct PicoVideo *pvid=&est->Pico->video; - const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid) - struct TileStrip ts; - int width, height, ymask; - int vscroll, htab; - - ts.hc=hcache; - ts.cells=maxcells; - - // Work out the TileStrip to draw - - // Work out the name table size: 32 64 or 128 tiles (0-3) - width=pvid->reg[16]; - height=(width>>4)&3; width&=3; - - ts.xmask=(1<reg[4]&0x07)<<12; // B - else ts.nametab=(pvid->reg[2]&0x38)<< 9; // A - - htab=pvid->reg[13]<<9; // Horizontal scroll table address - switch (pvid->reg[11]&3) { - case 1: htab += (est->DrawScanline<<1) & 0x0f; break; - case 2: htab += (est->DrawScanline<<1) & ~0x0f; break; // Offset by tile - case 3: htab += (est->DrawScanline<<1); break; // Offset by line - } - htab+=plane_sh&LF_PLANE; // A or B - - // Get horizontal scroll value, will be masked later - ts.hscroll = PicoMem.vram[htab & 0x7fff]; - - if((pvid->reg[12]&6) == 6) { - // interlace mode 2 - vscroll = PicoMem.vsram[plane_sh&LF_PLANE]; // Get vertical scroll value - - // Find the line in the name table - ts.line=(vscroll+(est->DrawScanline<<1))&((ymask<<1)|1); - ts.nametab+=(ts.line>>4)<reg[11]&4) { - // shit, we have 2-cell column based vscroll - // luckily this doesn't happen too often - ts.line=ymask|(shift[width]<<24); // save some stuff instead of line - // vscroll value for leftmost cells in case of hscroll not on 16px boundary - // XXX it's unclear what exactly the hw is doing. Continue reading where it - // stopped last seems to work best (H40: 0x50 (wrap->0x00), H32 0x40). - plane_sh |= PicoMem.vsram[(pvid->reg[12]&1?0x00:0x20) + (plane_sh&LF_PLANE)] << 16; - DrawStripVSRam(&ts, plane_sh, cellskip); - } else { - vscroll = PicoMem.vsram[plane_sh&LF_PLANE]; // Get vertical scroll value - - // Find the line in the name table - ts.line=(vscroll+est->DrawScanline)&ymask; - ts.nametab+=(ts.line>>3)<Pico->video; \ + const char shift[4]={5,6,5,7}; /* 32,64 or 128 sized tilemaps (2 is invalid) */ \ + struct TileStrip ts; \ + int width, height, ymask; \ + int vscroll, htab; \ + \ + ts.hc=hcache; \ + ts.cells=maxcells; \ + \ + /* Work out the TileStrip to draw */ \ + \ + /* Work out the name table size: 32 64 or 128 tiles (0-3) */ \ + width=pvid->reg[16]; \ + height=(width>>4)&3; width&=3; \ + \ + ts.xmask=(1<reg[4]&0x07)<<12; /* B */ \ + else ts.nametab=(pvid->reg[2]&0x38)<< 9; /* A */ \ + \ + htab=pvid->reg[13]<<9; /* Horizontal scroll table address */ \ + switch (pvid->reg[11]&3) { \ + case 1: htab += (est->DrawScanline<<1) & 0x0f; break; \ + case 2: htab += (est->DrawScanline<<1) & ~0x0f; break; /* Offset by tile */ \ + case 3: htab += (est->DrawScanline<<1); break; /* Offset by line */ \ + } \ + htab+=plane_sh&LF_PLANE; /* A or B */ \ + \ + /* Get horizontal scroll value, will be masked later */ \ + ts.hscroll = PicoMem.vram[htab & 0x7fff]; \ + \ + if (likely(!(pvid->reg[11]&4))) { \ + vscroll = PicoMem.vsram[plane_sh&LF_PLANE]; /* Get vertical scroll value */ \ + \ + if(likely((pvid->reg[12]&6) != 6)) { \ + /* Find the line in the name table */ \ + ts.line=(vscroll+est->DrawScanline)&ymask; \ + ts.nametab+=(ts.line>>3)<DrawScanline<<1))&((ymask<<1)|1); \ + ts.nametab+=(ts.line>>4)<0x00), H32 0x40). */ \ + plane_sh |= PicoMem.vsram[(pvid->reg[12]&1?0x00:0x20) + (plane_sh&LF_PLANE)] << 16; \ + \ + if (likely((pvid->reg[12]&6) != 6)) { \ + ts.line=ymask|(shift[width]<<24); /* save some stuff instead of line */ \ + drawstripvsram(&ts, plane_sh, cellskip); \ + } else { \ + ts.line=(ymask<<1)|1|(shift[width]<<24); /* save some stuff instead of line */ \ + drawstripvsraminterlace(&ts, plane_sh, cellskip); \ + } \ + } \ } +#ifndef _ASM_DRAW_C +static DrawLayerMaker(DrawLayer,DrawStrip,DrawStripInterlace,DrawStripVSRam,DrawStripVSRamInterlace); // -------------------------------------------- @@ -697,39 +598,42 @@ static void DrawWindow(int tstart, int tend, int prio, int sh, { unsigned char *pd = est->HighCol; struct PicoVideo *pvid = &est->Pico->video; - int tilex,ty,nametab,code=0; - int blank=-1; // The tile we know is blank + int tilex,ty,nametab,code,oldcode=-1,blank=-1; // The tile we know is blank + int yshift,ymask; + u32 pack; + u32 *hc=NULL, lflags=0; // referenced in DrawTile + + yshift = 4, ymask = 0x7; + if(likely((pvid->reg[12]&6) == 6)) + yshift = 5, ymask = 0xf; + ty=((est->DrawScanline<<(yshift-4))&ymask)<<1; // Y-Offset into tile // Find name table line: if (pvid->reg[12]&1) { nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode - nametab+=(est->DrawScanline>>3)<<6; + nametab+=(est->DrawScanline>>(yshift-1))<<6; } else { nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode - nametab+=(est->DrawScanline>>3)<<5; + nametab+=(est->DrawScanline>>(yshift-1))<<5; } - tilex=tstart<<1; - if (prio && !(est->rendstatus & PDRAW_WND_DIFF_PRIO)) { // all tiles processed in low prio pass return; } + tilex=tstart<<1; tend<<=1; - ty=(est->DrawScanline&7)<<1; // Y-Offset into tile // Draw tiles across screen: if (!sh) { for (; tilex < tend; tilex++) { - unsigned int pack; - int dx, addr; - int pal; + int dx, pal; code = PicoMem.vram[nametab + tilex]; if ((code>>15) != prio) { @@ -738,30 +642,16 @@ static void DrawWindow(int tstart, int tend, int prio, int sh, } if (code==blank) continue; - // Get tile address/2: - addr=(code&0x7ff)<<4; - if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip - - pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); - if (!pack) { - blank = code; - continue; - } - - pal = ((code >> 9) & 0x30); dx = 8 + (tilex << 3); - if (code & 0x0800) TileFlip(pd + dx, pack, pal); - else TileNorm(pd + dx, pack, pal); + DrawTile(~0,yshift,ymask,code,0); } } else { for (; tilex < tend; tilex++) { - unsigned int pack; - int dx, addr; - int pal; + int dx, pal; code = PicoMem.vram[nametab + tilex]; if((code>>15) != prio) { @@ -779,21 +669,9 @@ static void DrawWindow(int tstart, int tend, int prio, int sh, pal |= 0x80; } if(code==blank) continue; - - // Get tile address/2: - addr=(code&0x7ff)<<4; - if (code&0x1000) addr+=14-ty; else addr+=ty; // Y-flip - - pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); - if (!pack) { - blank = code; - continue; - } - dx = 8 + (tilex << 3); - if (code & 0x0800) TileFlip(pd + dx, pack, pal); - else TileNorm(pd + dx, pack, pal); + DrawTile(~0,yshift,ymask,code,0); } } } @@ -803,10 +681,8 @@ static void DrawWindow(int tstart, int tend, int prio, int sh, static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est) { unsigned char *pd = est->HighCol; - u32 code, dx; - u32 pack; - int pal; - int hs; + u32 code, dx, pack; + int pal, hs; // *ts->hc++ = code | (dx<<16) | (ty<<26); // cache it @@ -817,7 +693,7 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est // we can process whole line and then act as if sh/hi mode was off, // but leave lo pri op sprite markers alone int *zb = (int *)(Pico.est.HighCol+8); - int c = 320/4; + int c = 320 / 4; while (c--) { *zb++ &= 0x7f7f7f7f; @@ -830,11 +706,8 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est if (!sh) { while ((code=*hc++)) { - dx = (code >> 16) & 0x1ff; pack = *hc++; - if (!pack) - continue; - + dx = (code >> 16) & 0x1ff; pal = ((code >> 9) & 0x30); if (code & 0x0800) TileFlip(pd + dx, pack, pal); @@ -846,28 +719,34 @@ static void DrawTilesFromCache(u32 *hc, int sh, int rlim, struct PicoEState *est while ((code=*hc++)) { unsigned char *zb; - dx = (code >> 16) & 0x1ff; pack = *hc++; + dx = (code >> 16) & 0x1ff; + pal = ((code >> 9) & 0x30); zb = est->HighCol+dx; - if (likely(~code&(1<<25))) { + if (likely(~code & (1<<25))) { *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; *zb++ &= 0x7f; } else { hs = dx & 7; if (*hc == 0) // last tile? - for ( pal = hs; pal < 8; pal++) *zb++ &= 0x7f; - else // first tile - for (zb += 8-hs, pal = 0; pal < hs; pal++) *zb++ &= 0x7f; + switch (8-hs) { case 7: *zb++ &= 0x7f; + case 6: *zb++ &= 0x7f; case 5: *zb++ &= 0x7f; case 4: *zb++ &= 0x7f; + case 3: *zb++ &= 0x7f; case 2: *zb++ &= 0x7f; case 1: *zb++ &= 0x7f; + } + else { // first tile + zb += 8-hs; + switch (hs) { case 7: *zb++ &= 0x7f; + case 6: *zb++ &= 0x7f; case 5: *zb++ &= 0x7f; case 4: *zb++ &= 0x7f; + case 3: *zb++ &= 0x7f; case 2: *zb++ &= 0x7f; case 1: *zb++ &= 0x7f; + } + } } - if (!pack) - continue; - - pal = ((code >> 9) & 0x30); - - if (code & 0x0800) TileFlip(pd + dx, pack, pal); - else TileNorm(pd + dx, pack, pal); + if (pack) { + if (code & 0x0800) TileFlip(pd + dx, pack, pal); + else TileNorm(pd + dx, pack, pal); + } } } } @@ -1180,211 +1059,33 @@ static void DrawSpritesHiAS(unsigned char *sprited, int sh) #ifdef FORCE // NB lots of duplicate code, all for the sake of a small performance gain. -static void DrawStripForced(struct TileStrip *ts, int cellskip) -{ - unsigned char *pd = Pico.est.HighCol; - int tilex, dx, ty, addr=0, cells; - u32 code = 0, oldcode = -1; - int pal = 0; - - // Draw tiles across screen: - tilex=((-ts->hscroll)>>3)+cellskip; - ty=(ts->line&7)<<1; // Y-Offset into tile - dx=((ts->hscroll-1)&7)+1; - cells = ts->cells - cellskip; - if(dx != 8) cells++; // have hscroll, need to draw 1 cell more - dx+=cellskip<<3; - - for (; cells > 0; dx+=8, tilex++, cells--) - { - u32 pack; - - code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; - - if (code!=oldcode) { - oldcode = code; - // Get tile address/2: - addr = ((code&0x7ff)<<4) + ty; - if (code & 0x1000) addr^=0xe; // Y-flip - - pal = (code>>9)&0x30; - } - - pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); - - if (code & 0x0800) TileFlip_and(pd + dx, pack, pal); - else TileNorm_and(pd + dx, pack, pal); - } -} - -static void DrawStripVSRamForced(struct TileStrip *ts, int plane_sh, int cellskip) -{ - unsigned char *pd = Pico.est.HighCol; - int tilex, dx, ty=0, addr=0, cell=0, nametabadd=0; - u32 code=0, oldcode=-1; - int pal=0, scan=Pico.est.DrawScanline, plane; - - // Draw tiles across screen: - plane = plane_sh & LF_PLANE; - tilex=(-ts->hscroll)>>3; - dx=((ts->hscroll-1)&7)+1; - if (ts->hscroll & 0x0f) { - int adj = ((ts->hscroll ^ dx) >> 3) & 1; - cell -= adj + 1; - ts->cells -= adj; - PicoMem.vsram[0x3e] = PicoMem.vsram[0x3f] = plane_sh >> 16; - } - cell+=cellskip; - tilex+=cellskip; - dx+=cellskip<<3; - - if ((cell&1)==1) - { - int line,vscroll; - vscroll = PicoMem.vsram[plane + (cell&0x3e)]; - - // Find the line in the name table - line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. - nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] - ty=(line&7)<<1; // Y-Offset into tile - } - for (; cell < ts->cells; dx+=8,tilex++,cell++) - { - unsigned int pack; - - if ((cell&1)==0) - { - int line,vscroll; - vscroll = PicoMem.vsram[plane + (cell&0x3e)]; - - // Find the line in the name table - line=(vscroll+scan)&ts->line&0xffff; // ts->line is really ymask .. - nametabadd=(line>>3)<<(ts->line>>24); // .. and shift[width] - ty=(line&7)<<1; // Y-Offset into tile - } - - code=PicoMem.vram[ts->nametab+nametabadd+(tilex&ts->xmask)]; - - if (code!=oldcode) { - oldcode = code; - // Get tile address/2: - addr=(code&0x7ff)<<4; - - pal = (code>>9)&0x30; // shadow - } - - pack = code & 0x1000 ? ty^0xe : ty; // Y-flip - pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr+pack)); - - if (code & 0x0800) TileFlip_and(pd + dx, pack, pal); - else TileNorm_and(pd + dx, pack, pal); - } -} - -void DrawStripInterlaceForced(struct TileStrip *ts) -{ - unsigned char *pd = Pico.est.HighCol; - int tilex = 0, dx = 0, ty = 0, cells; - int oldcode = -1; - unsigned int pal = 0, pack = 0; - - // Draw tiles across screen: - tilex=(-ts->hscroll)>>3; - ty=(ts->line&15)<<1; // Y-Offset into tile - dx=((ts->hscroll-1)&7)+1; - cells = ts->cells; - if(dx != 8) cells++; // have hscroll, need to draw 1 cell more - - for (; cells; dx+=8,tilex++,cells--) - { - u32 code = PicoMem.vram[ts->nametab + (tilex & ts->xmask)]; - - if (code!=oldcode) { - oldcode = code; - - // Get tile address/2: - u32 addr = ((code&0x3ff)<<5) + ty; - if (code & 0x1000) addr ^= 0x1e; // Y-flip - - pal = (code>>9)&0x30; // shadow - - pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); - } - - if (code & 0x0800) TileFlip_and(pd + dx, pack, pal); - else TileNorm_and(pd + dx, pack, pal); - } +// Forced tile drawing, without any masking and blank handling +#define DrawTileForced(mask,yshift,ymask,hpcode,cache) { \ + if (code!=oldcode) { \ + oldcode = code; \ + \ + /* Get tile address/2: */ \ + u32 addr = ((code<>9)&0x30); \ + pal |= 0xc0; /* leave s/h bits untouched in pixel "and" */ \ + \ + pack = CPU_LE2(*(u32 *)(PicoMem.vram + addr)); \ + } \ + if (code & 0x0800) TileFlip_and(pd + dx, pack, pal); \ + else TileNorm_and(pd + dx, pack, pal); \ } -// XXX only duplicated to avoid ARM asm hassles -static void DrawLayerForced(int plane_sh, int cellskip, int maxcells, - struct PicoEState *est) -{ - struct PicoVideo *pvid=&est->Pico->video; - const char shift[4]={5,6,5,7}; // 32,64 or 128 sized tilemaps (2 is invalid) - struct TileStrip ts; - int width, height, ymask; - int vscroll, htab; +static DrawStripMaker(DrawStripForced, 4, 0x7, 0, DrawTileForced, 0); - ts.cells=maxcells; +static DrawStripMaker(DrawStripInterlaceForced, 5, 0xf, 0, DrawTileForced, 0); - // Work out the TileStrip to draw +static DrawStripVSRamMaker(DrawStripVSRamForced, 4, 0x7, 0, DrawTileForced, 0); - // Work out the name table size: 32 64 or 128 tiles (0-3) - width=pvid->reg[16]; - height=(width>>4)&3; width&=3; - - ts.xmask=(1<reg[4]&0x07)<<12; // B - else ts.nametab=(pvid->reg[2]&0x38)<< 9; // A - - htab=pvid->reg[13]<<9; // Horizontal scroll table address - switch (pvid->reg[11]&3) { - case 1: htab += (est->DrawScanline<<1) & 0x0f; break; - case 2: htab += (est->DrawScanline<<1) & ~0x0f; break; // Offset by tile - case 3: htab += (est->DrawScanline<<1); break; // Offset by line - } - htab+=plane_sh&1; // A or B - - // Get horizontal scroll value, will be masked later - ts.hscroll = PicoMem.vram[htab & 0x7fff]; - - if((pvid->reg[12]&6) == 6) { - // interlace mode 2 - vscroll = PicoMem.vsram[plane_sh & 1]; // Get vertical scroll value - - // Find the line in the name table - ts.line=(vscroll+(est->DrawScanline<<1))&((ymask<<1)|1); - ts.nametab+=(ts.line>>4)<reg[11]&4) { - // shit, we have 2-cell column based vscroll - // luckily this doesn't happen too often - ts.line=ymask|(shift[width]<<24); // save some stuff instead of line - // vscroll value for leftmost cells in case of hscroll not on 16px boundary - // XXX it's unclear what exactly the hw is doing. Continue reading where it - // stopped last seems to work best (H40: 0x50 (wrap->0x00), H32 0x40). - plane_sh |= PicoMem.vsram[(pvid->reg[12]&1?0x00:0x20) + (plane_sh&1)] << 16; - DrawStripVSRamForced(&ts, plane_sh, cellskip); - } else { - vscroll = PicoMem.vsram[plane_sh & 1]; // Get vertical scroll value - - // Find the line in the name table - ts.line=(vscroll+est->DrawScanline)&ymask; - ts.nametab+=(ts.line>>3)<>9)&0x30; + pal |= 0xc0; // leave s/h bits untouched in pixel "and" if (code&0x800) fTileFunc = TileFlipSH_AS_and; else fTileFunc = TileNormSH_AS_and; @@ -1455,7 +1157,7 @@ static void DrawSpritesForced(unsigned char *sprited) } // anything not covered by a sprite is off - // XXX Titan hw notes say that transparent pixels remove shadow. Is this also + // TODO Titan hw notes say that transparent pixels remove shadow. Is this also // the case in areas where no sprites are displayed? for (cnt = 1; cnt < sizeof(mb)-1; cnt++) if (mb[cnt] == 0xff) { @@ -1984,7 +1686,7 @@ static int DrawDisplay(int sh) DrawWindow(0, maxcells>>1, 1, sh, est); else if (hvwind == 2) { if (HighCacheA[0]) - DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : -edge<<4, est); + DrawTilesFromCache(HighCacheA, sh, (win&0x80) ? edge<<4 : maxw, est); DrawWindow((win&0x80) ? edge : 0, (win&0x80) ? maxcells>>1 : edge, 1, sh, est); } else if (HighCacheA[0]) @@ -2005,10 +1707,11 @@ static int DrawDisplay(int sh) #ifdef FORCE if (pvid->debug_p & PVD_FORCE_B) { lflags = LF_PLANE_B | (sh<<1); - DrawLayerForced(lflags, 0, maxcells, est); + DrawLayerForced(lflags, NULL, 0, maxcells, est); } else if (pvid->debug_p & PVD_FORCE_A) { + // TODO what happens in windowed mode? lflags = LF_PLANE_A | (sh<<1); - DrawLayerForced(lflags, 0, maxcells, est); + DrawLayerForced(lflags, NULL, 0, maxcells, est); } else if (pvid->debug_p & PVD_FORCE_S) DrawSpritesForced(sprited); #endif