From: notaz Date: Wed, 2 Jul 2008 19:34:34 +0000 (+0000) Subject: sprite binning wip X-Git-Tag: v1.85~448 X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d9fc2fe1ac69169861cb60b62ccc9fbc6e4fd4c6;p=picodrive.git sprite binning wip git-svn-id: file:///home/notaz/opt/svn/PicoDrive@514 be3aeb3a-fb24-0410-a615-afba39da0efa --- diff --git a/Pico/Draw.c b/Pico/Draw.c index 0c5f1781..d9f4a8ac 100644 --- a/Pico/Draw.c +++ b/Pico/Draw.c @@ -38,10 +38,12 @@ static int HighCacheS[80+1]; // and sprites static int HighPreSpr[80*2+1]; // slightly preprocessed sprites int *HighCacheS_ptr; +#define MAX_LINE_SPRITES 30 +static unsigned char HighLnSpr[240][2 + MAX_LINE_SPRITES]; // sprite_count, tile_count, [spritep]... + int rendstatus = 0; int DrawScanline = 0; -static int SpriteBlocks; static int skip_next_line=0; //unsigned short ppt[] = { 0x0f11, 0x0ff1, 0x01f1, 0x011f, 0x01ff, 0x0f1f, 0x0f0e, 0x0e7c }; @@ -924,15 +926,24 @@ static void DrawSpritesFromCacheAS(int *hc, int maxwidth, int prio, int sh) // Index + 0 : ----hhvv -lllllll -------y yyyyyyyy // Index + 4 : -------x xxxxxxxx pccvhnnn nnnnnnnn // v -// Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size +// Index + 0 : hhhhvvvv ----hhvv yyyyyyyy yyyyyyyy // v, h: vert./horiz. size // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 static void PrepareSprites(int full) { struct PicoVideo *pvid=&Pico.video; - int u=0,link=0,sblocks=0; + int u,link=0; int table=0; int *pd = HighPreSpr; + int max_lines = 224, max_sprites = 80; + int max_line_sprites = 20; // 20 sprites, 40 tiles + + if (!(Pico.video.reg[12]&1)) + max_sprites = 64, max_line_sprites = 16; + if (PicoOpt & POPT_DIS_SPRITE_LIM) + max_line_sprites = MAX_LINE_SPRITES; + + if (pvid->reg[1]&8) max_lines = 240; table=pvid->reg[5]&0x7f; if (pvid->reg[12]&1) table&=0x7e; // Lowest bit 0 in 40-cell mode @@ -942,41 +953,60 @@ static void PrepareSprites(int full) { int pack; // updates: tilecode, sx - for (u=0; u < 80 && (pack = *pd); u++, pd+=2) + for (u=0; u < max_lines && (pack = *pd); u++, pd+=2) { unsigned int *sprite; - int code, code2, sx, sy, skip=0; + int code2, sx, sy, height; sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite // parse sprite info - code = sprite[0]; code2 = sprite[1]; - code2 &= ~0xfe000000; - code2 -= 0x00780000; // Get X coordinate + 8 in upper 16 bits - sx = code2>>16; + sx = (code2>>16)&0x1ff; + sx -= 0x78; // Get X coordinate + 8 + sy = (pack << 16) >> 16; + height = pack >> 28; - if((sx <= 8-((pack>>28)<<3) && sx >= -0x76) || sx >= 328) skip=1<<23; - else if ((sy = (pack<<16)>>16) < 240 && sy > -32) { - int sbl = (2<<(pack>>28))-1; - sblocks |= sbl<<(sy>>3); + if (sy < max_lines && sy + (height<<3) > DrawScanline && // sprite onscreen (y)? + (sx > -24 || sx < 328)) // onscreen x + { + int y = (sy >= DrawScanline) ? sy : DrawScanline; + for (; y < sy + (height<<3) && y < max_lines; y++) + { + int i, cnt, offs; + cnt = HighLnSpr[y][0] & 0x7f; + if (cnt >= max_line_sprites) continue; // sprite limit? + offs = (pd - HighPreSpr) / 2; + + for (i = 0; i < cnt; i++) + if (HighLnSpr[y][2+i] == offs) goto found; + + // this sprite was previously missing + HighLnSpr[y][2+cnt] = offs; + HighLnSpr[y][0] = cnt + 1; +found:; + } } - *pd = (pack&~(1<<23))|skip; - *(pd+1) = code2; + code2 &= ~0xfe000000; + code2 -= 0x00780000; // Get X coordinate + 8 in upper 16 bits + pd[1] = code2; // Find next sprite - link=(code>>16)&0x7f; - if(!link) break; // End of sprites + link=(sprite[0]>>16)&0x7f; + if (!link) break; // End of sprites } - SpriteBlocks |= sblocks; } else { - for (; u < 80; u++) + for (u = 0; u < max_lines; u++) + *((int *)&HighLnSpr[u][0]) = 0; + + for (u = 0; u < max_lines; u++) { unsigned int *sprite; - int code, code2, sx, sy, hv, height, width, skip=0, sx_min; + int code, code2, sx, sy, hv, height, width; + int sx_min, offscr_x; sprite=(unsigned int *)(Pico.vram+((table+(link<<2))&0x7ffc)); // Find sprite @@ -986,103 +1016,92 @@ static void PrepareSprites(int full) hv = (code>>24)&0xf; height = (hv&3)+1; - if (sy > 240 || sy + (height<<3) <= 0) skip|=1<<22; // sprite offscreen (completely, y) - width = (hv>>2)+1; code2 = sprite[1]; sx = (code2>>16)&0x1ff; sx -= 0x78; // Get X coordinate + 8 sx_min = 8-(width<<3); - if ((sx <= sx_min && sx >= -0x76) || sx >= 328) skip|=1<<23; // offscreen x - else if (sx > sx_min && !skip) { - int sbl = (2<>3; - if(shi < 0) shi=0; // negative sy - sblocks |= sbl<= 328; + + if (sy < max_lines && sy + (height<<3) > DrawScanline) // sprite onscreen (y)? + { + int y = (sy >= DrawScanline) ? sy : DrawScanline; + for (; y < sy + (height<<3) && y < max_lines; y++) + { + int cnt = HighLnSpr[y][0]; + if (cnt >= max_line_sprites) continue; // sprite limit? + + if (HighLnSpr[y][1] >= max_line_sprites*2) { // tile limit? + HighLnSpr[y][0] |= 0x80; + continue; + } + HighLnSpr[y][1] += width; + + if (sx == -0x78) { + if (cnt > 0) + HighLnSpr[y][0] |= 0x80; // masked, no more sprites for this line + continue; + } + // must keep the first sprite even if it's offscreen, for masking + if (cnt > 0 && (sx <= sx_min || sx >= 328)) continue; // offscreen x + + HighLnSpr[y][2+cnt] = ((pd - HighPreSpr) / 2); // | prio; + HighLnSpr[y][0] = cnt + 1; + } } - *pd++ = (width<<28)|(height<<24)|skip|(hv<<16)|((unsigned short)sy); + *pd++ = (width<<28)|(height<<24)|(hv<<16)|((unsigned short)sy); *pd++ = (sx<<16)|((unsigned short)code2); // Find next sprite link=(code>>16)&0x7f; - if(!link) break; // End of sprites + if (!link) break; // End of sprites } - SpriteBlocks = sblocks; - *pd = 0; // terminate + *pd = 0; + +#if 0 + for (u = 0; u < max_lines; u++) + { + int y; + printf("c%03i: %2i, %2i: ", u, HighLnSpr[u][0] & 0x7f, HighLnSpr[u][1]); + for (y = 0; y < HighLnSpr[u][0] & 0x7f; y++) + printf(" %i", HighLnSpr[u][y+2]); + printf("\n"); + } +#endif } } static void DrawAllSprites(int *hcache, int maxwidth, int prio, int sh) { - int i,u,n; - int sx1seen = 0; // sprite with x coord 1 or 0 seen - int ntiles = 0; // tile counter for sprite limit emulation - int *sprites[40]; // Sprites to draw in fast mode - int max_line_sprites = 20; // 20 sprites, 40 tiles - int *ps, pack, rs = rendstatus, scan = DrawScanline; + int rs = rendstatus, scan = DrawScanline; + unsigned char *p; + int cnt, as; if (rs & (PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES)) { - //dprintf("PrepareSprites(%i) [%i]", (rs>>4)&1, scan); + //elprintf(EL_STATUS, "PrepareSprites(%i)", (rs>>4)&1); PrepareSprites(rs & PDRAW_DIRTY_SPRITES); rendstatus = rs & ~(PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES); } - if (!(SpriteBlocks & (1<<(scan>>3)))) { *hcache = 0; return; } - - if (PicoOpt & POPT_DIS_SPRITE_LIM) - max_line_sprites = 80; HighCacheS_ptr = hcache; - ps = HighPreSpr; + cnt = HighLnSpr[scan][0] & 0x7f; - // Index + 0 : hhhhvvvv ab--hhvv yyyyyyyy yyyyyyyy // a: offscreen h, b: offs. v, h: horiz. size - // Index + 4 : xxxxxxxx xxxxxxxx pccvhnnn nnnnnnnn // x: x coord + 8 - - for (i=u=n=0; (pack = *ps) && n < max_line_sprites; ps+=2, u++) + if (cnt != 0) { - int sx, sy, row, pack2; - - if (pack & 0x00400000) continue; - - // get sprite info - pack2 = *(ps+1); - sx = pack2>>16; - sy = (pack <<16)>>16; - row = scan-sy; - - // elprintf(EL_ANOMALY, "x: %4i y: %4i p %i %ix%i", sx, sy, (pack2>>15)&1, (pack>>28)<<3, (pack>>21)&0x38); - - if (sx == -0x77) sx1seen|=1; // for masking mode 2 + p = &HighLnSpr[scan][2]; + as = (rs & PDRAW_ACC_SPRITES) ? 1 : 0; - // check if it is on this line - if (row < 0 || row >= ((pack>>21)&0x38)) continue; // no - - // masking sprite? - if (sx == -0x78) { - if (n > 0) break; // masked - continue; + // Go through sprites backwards: + for (cnt--; cnt >= 0; cnt--) + { + int offs = p[cnt] * 2; + //if ((p[cnt] & 0x80) && !as) continue; + DrawSprite(HighPreSpr + offs, sh, as); } - - n++; // number of sprites on this line (both visible and hidden, except of x=0) - - // sprite limit - ntiles += pack>>28; - if (ntiles > max_line_sprites*2) break; - - if (pack & 0x00800000) continue; - - // sprite is good, save it's pointer - sprites[i++]=ps; } - n = (rs & PDRAW_ACC_SPRITES) ? 1 : 0; - - // Go through sprites backwards: - for (i--; i>=0; i--) - DrawSprite(sprites[i],sh,n); - - // terminate cache list *HighCacheS_ptr = 0; } @@ -1351,9 +1370,9 @@ PICO_INTERNAL void PicoFrameStart(void) if (Pico.m.dirtyPal) Pico.m.dirtyPal = 2; // reset dirty if needed + DrawScanline=0; PrepareSprites(1); skip_next_line=0; - DrawScanline=0; } static void PicoLine(void) diff --git a/Pico/Pico.c b/Pico/Pico.c index 9f5a3612..77f20231 100644 --- a/Pico/Pico.c +++ b/Pico/Pico.c @@ -1,7 +1,7 @@ -// This is part of Pico Library +// PicoDrive // (c) Copyright 2004 Dave, All rights reserved. -// (c) Copyright 2006 notaz, All rights reserved. +// (c) Copyright 2006-2008 notaz, All rights reserved. // Free for non-commercial use. // For commercial use, separate licencing terms must be obtained. diff --git a/Pico/VideoPort.c b/Pico/VideoPort.c index 7a38ea9c..d027ca3b 100644 --- a/Pico/VideoPort.c +++ b/Pico/VideoPort.c @@ -1,7 +1,7 @@ -// This is part of Pico Library +// PicoDrive // (c) Copyright 2004 Dave, All rights reserved. -// (c) Copyright 2006-2007, Grazvydas "notaz" Ignotas +// (c) Copyright 2006-2008, Grazvydas "notaz" Ignotas // Free for non-commercial use. // For commercial use, separate licencing terms must be obtained.