From b6d7ac70909e29ba8f40d6eaee53dd5b1bb71e52 Mon Sep 17 00:00:00 2001 From: notaz Date: Tue, 1 Jul 2008 13:42:12 +0000 Subject: [PATCH] line draw deferment implemented git-svn-id: file:///home/notaz/opt/svn/PicoDrive@508 be3aeb3a-fb24-0410-a615-afba39da0efa --- Pico/Draw.c | 86 +++++++++++++++++++++++++------------------ Pico/Draw.s | 16 ++++---- Pico/Pico.c | 2 + Pico/Pico.h | 1 - Pico/PicoFrameHints.c | 31 +++++++--------- Pico/PicoInt.h | 3 +- Pico/VideoPort.c | 73 +++++++++++++++++++++--------------- Pico/sound/ym2612.c | 7 +--- 8 files changed, 120 insertions(+), 99 deletions(-) diff --git a/Pico/Draw.c b/Pico/Draw.c index 47edb759..0390d843 100644 --- a/Pico/Draw.c +++ b/Pico/Draw.c @@ -39,7 +39,7 @@ static int HighPreSpr[80*2+1]; // slightly preprocessed sprites int *HighCacheS_ptr; int rendstatus = 0; -int Scanline = 0; // Scanline +int DrawScanline = 0; static int SpriteBlocks; static int skip_next_line=0; @@ -252,7 +252,7 @@ void DrawStripVSRam(struct TileStrip *ts, int plane_sh, int cellskip) { int tilex,dx,code=0,addr=0,cell=0; int oldcode=-1,blank=-1; // The tile we know is blank - int pal=0,scan=Scanline; + int pal=0,scan=DrawScanline; // Draw tiles across screen: tilex=(-ts->hscroll)>>3; @@ -387,7 +387,7 @@ static void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells) else ts.nametab=(pvid->reg[2]&0x38)<< 9; // A htab=pvid->reg[13]<<9; // Horizontal scroll table address - if ( pvid->reg[11]&2) htab+=Scanline<<1; // Offset by line + if ( pvid->reg[11]&2) htab+=DrawScanline<<1; // Offset by line if ((pvid->reg[11]&1)==0) htab&=~0xf; // Offset by tile htab+=plane_sh&1; // A or B @@ -399,7 +399,7 @@ static void DrawLayer(int plane_sh, int *hcache, int cellskip, int maxcells) vscroll=Pico.vsram[plane_sh&1]; // Get vertical scroll value // Find the line in the name table - ts.line=(vscroll+(Scanline<<1))&((ymask<<1)|1); + ts.line=(vscroll+(DrawScanline<<1))&((ymask<<1)|1); ts.nametab+=(ts.line>>4)<>3)<reg[12]&1) { nametab=(pvid->reg[3]&0x3c)<<9; // 40-cell mode - nametab+=(Scanline>>3)<<6; + nametab+=(DrawScanline>>3)<<6; } else { nametab=(pvid->reg[3]&0x3e)<<9; // 32-cell mode - nametab+=(Scanline>>3)<<5; + nametab+=(DrawScanline>>3)<<5; } tilex=tstart<<1; @@ -451,7 +451,7 @@ static void DrawWindow(int tstart, int tend, int prio, int sh) // int *hcache } tend<<=1; - ty=(Scanline&7)<<1; // Y-Offset into tile + ty=(DrawScanline&7)<<1; // Y-Offset into tile // Draw tiles across screen: if (!sh) @@ -643,7 +643,7 @@ static void DrawSprite(int *sprite, int sh, int as) height=(sy>>24)&7; // Width and height in tiles sy=(sy<<16)>>16; // Y - row=Scanline-sy; // Row of the sprite we are on + row=DrawScanline-sy; // Row of the sprite we are on if (code&0x1000) row=(height<<3)-1-row; // Flip Y @@ -699,7 +699,7 @@ static void DrawSpriteInterlace(unsigned int *sprite) width=(height>>2)&3; height&=3; width++; height++; // Width and height in tiles - row=(Scanline<<1)-sy; // Row of the sprite we are on + row=(DrawScanline<<1)-sy; // Row of the sprite we are on code=sprite[1]; sx=((code>>16)&0x1ff)-0x78; // X @@ -731,7 +731,7 @@ static void DrawSpriteInterlace(unsigned int *sprite) static void DrawAllSpritesInterlace(int *hcache, int maxwidth, int pri, int sh) { struct PicoVideo *pvid=&Pico.video; - int i,u,table,link=0,sline=Scanline<<1; + int i,u,table,link=0,sline=DrawScanline<<1; unsigned int *sprites[80]; // Sprite index table=pvid->reg[5]&0x7f; @@ -1020,7 +1020,7 @@ static void DrawAllSprites(int *hcache, int maxwidth, int prio, int sh) 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 = Scanline; + int *ps, pack, rs = rendstatus, scan = DrawScanline; if (rs & (PDRAW_SPRITES_MOVED|PDRAW_DIRTY_SPRITES)) { //dprintf("PrepareSprites(%i) [%i]", (rs>>4)&1, scan); @@ -1212,7 +1212,7 @@ static void FinalizeLine8bit(int sh) int len, rs = rendstatus; static int dirty_count; - if (!sh && !(rs & PDRAW_ACC_SPRITES) && Pico.m.dirtyPal == 1 && Scanline < 222) + if (!sh && !(rs & PDRAW_ACC_SPRITES) && Pico.m.dirtyPal == 1 && DrawScanline < 222) { // a hack for mid-frame palette changes if (!(rs & PDRAW_SONIC_MODE)) @@ -1247,14 +1247,14 @@ static void FinalizeLine8bit(int sh) static void (*FinalizeLine)(int sh) = FinalizeLineBGR444; -// hblank was enabled early during prev line processng - -// it should have been blanked -static void handle_early_blank(int scanline, int sh) +// -------------------------------------------- + +static void DrawBlankedLine(void) { - scanline--; + int sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight? if (PicoScanBegin != NULL) - PicoScanBegin(scanline); + PicoScanBegin(DrawScanline); BackFill(Pico.video.reg[7], sh); @@ -1262,11 +1262,9 @@ static void handle_early_blank(int scanline, int sh) FinalizeLine(sh); if (PicoScanEnd != NULL) - PicoScanEnd(scanline); + PicoScanEnd(DrawScanline); } -// -------------------------------------------- - static int DrawDisplay(int sh, int as) { struct PicoVideo *pvid=&Pico.video; @@ -1285,8 +1283,8 @@ static int DrawDisplay(int sh, int as) win=pvid->reg[0x12]; edge=(win&0x1f)<<3; - if (win&0x80) { if (Scanline>=edge) hvwind=1; } - else { if (Scanline< edge) hvwind=1; } + if (win&0x80) { if (DrawScanline>=edge) hvwind=1; } + else { if (DrawScanline< edge) hvwind=1; } if (!hvwind) { // we might have a vertical window here win=pvid->reg[0x11]; @@ -1327,7 +1325,7 @@ static int DrawDisplay(int sh, int as) int *c, a, b; for (a = 0, c = HighCacheA; *c; c++, a++); for (b = 0, c = HighCacheB; *c; c++, b++); - printf("%i:%03i: a=%i, b=%i\n", Pico.m.frame_count, Scanline, a, b); + printf("%i:%03i: a=%i, b=%i\n", Pico.m.frame_count, DrawScanline, a, b); } #endif @@ -1354,24 +1352,19 @@ PICO_INTERNAL void PicoFrameStart(void) PrepareSprites(1); skip_next_line=0; + DrawScanline=0; } -PICO_INTERNAL int PicoLine(int scan) +static void PicoLine(void) { int sh, as = 0; - if (skip_next_line>0) { skip_next_line--; return 0; } // skip_next_line rendering lines + if (skip_next_line>0) { skip_next_line--; return; } // skip rendering lines - Scanline=scan; sh=(Pico.video.reg[0xC]&8)>>3; // shadow/hilight? if (rendstatus & PDRAW_ACC_SPRITES) as|=1; // accurate sprites - if (rendstatus & PDRAW_EARLY_BLANK) { - if (scan > 0) handle_early_blank(scan, sh); - rendstatus &= ~PDRAW_EARLY_BLANK; - } - if (PicoScanBegin != NULL) - skip_next_line = PicoScanBegin(scan); + skip_next_line = PicoScanBegin(DrawScanline); // Draw screen: BackFill(Pico.video.reg[7], sh|as); @@ -1382,11 +1375,32 @@ PICO_INTERNAL int PicoLine(int scan) FinalizeLine(sh); if (PicoScanEnd != NULL) - PicoScanEnd(scan); - - return 0; + PicoScanEnd(DrawScanline); } +void PicoDrawSync(int to, int blank_last_line) +{ + for (; DrawScanline < to; DrawScanline++) + { +#if !CAN_HANDLE_240_LINES + if (DrawScanline >= 224) break; +#endif + PicoLine(); + } + +#if !CAN_HANDLE_240_LINES + if (DrawScanline >= 224) DrawScanline = 240, return; +#endif + + // last line + if (DrawScanline <= to) + { + if (blank_last_line) + DrawBlankedLine(); + else PicoLine(); + DrawScanline++; + } +} void PicoDrawSetColorFormat(int which) { diff --git a/Pico/Draw.s b/Pico/Draw.s index 94739b86..46be65f1 100644 --- a/Pico/Draw.s +++ b/Pico/Draw.s @@ -11,7 +11,7 @@ .extern Pico .extern PicoOpt .extern HighCol -.extern Scanline +.extern DrawScanline .extern HighSprZ .extern rendstatus .extern DrawLineDest @@ -316,7 +316,7 @@ DrawLayer: ldreqb r12, [r11, #2] ldrneb r12, [r11, #4] - ldr r2, =Scanline @ trying to make good use of pipeline here + ldr r2, =DrawScanline @ trying to make good use of pipeline here ldr lr, =(Pico+0x10000) @ lr=Pico.vram moveq r12, r12, lsl #10 @@ -330,7 +330,7 @@ DrawLayer: mov r4, r8, lsr #8 @ pvid->reg[13] mov r4, r4, lsl #10 @ htab=pvid->reg[13]<<9; (halfwords) tst r7, #2 - addne r4, r4, r2, lsl #2 @ htab+=Scanline<<1; // Offset by line + addne r4, r4, r2, lsl #2 @ htab+=DrawScanline<<1; // Offset by line tst r7, #1 biceq r4, r4, #0x1f @ htab&=~0xf; // Offset by tile add r4, r4, r0, lsl #1 @ htab+=plane @@ -513,7 +513,7 @@ DrawLayer: bic r8, r8, #0x3fc00000 orr r8, r8, r5, lsl #25 @ r8=(xmask[31:25]|had_output[24]|tilex[21:0]) - ldr r4, =Scanline + ldr r4, =DrawScanline orr r5, r1, r10, lsl #24 ldr r4, [r4] sub r1, r3, #1 @@ -690,7 +690,7 @@ DrawLayer: movne r7, r7, lsl #5 @ Find the line in the name table - add r2, r7, r2, lsl #22 @ r2=(vscroll+(Scanline<<1))<<21 (11 bits); + add r2, r7, r2, lsl #22 @ r2=(vscroll+(DrawScanline<<1))<<21 (11 bits); orr r1, r1, #0x80000000 and r2, r2, r1, ror #10 @ &((ymask<<1)|1)<<21; mov r2, r2, lsr #21 @@ -1097,7 +1097,7 @@ DrawSprite: orr r8, r2, r1, lsl #4 ldr r3, [r0] @ sprite[0] - ldr r7, =Scanline + ldr r7, =DrawScanline mov r6, r3, lsr #28 sub r6, r6, #1 @ r6=width-1 (inc later) mov r5, r3, lsr #24 @@ -1107,7 +1107,7 @@ DrawSprite: ldr r7, [r7] ldr r9, [r0, #4] - sub r7, r7, r4, asr #16 @ r7=row=Scanline-sy + sub r7, r7, r4, asr #16 @ r7=row=DrawScanline-sy mov r2, r9, asr #16 @ r2=sx mov r9, r9, lsl #16 @@ -1266,7 +1266,7 @@ DrawWindow: stmfd sp!, {r4-r11,lr} ldr r11, =(Pico+0x22228) @ Pico.video - ldr r10, =Scanline + ldr r10, =DrawScanline ldrb r12, [r11, #3] @ pvid->reg[3] ldr r10, [r10] diff --git a/Pico/Pico.c b/Pico/Pico.c index a7930fc7..58c1a354 100644 --- a/Pico/Pico.c +++ b/Pico/Pico.c @@ -424,6 +424,7 @@ static int PicoFrameSimple(void) if (!(PicoOpt&POPT_ALT_RENDERER)) { // Draw the screen +#if 0 #if CAN_HANDLE_240_LINES if (pv->reg[1]&8) { for (y=0;y<240;y++) PicoLine(y); @@ -432,6 +433,7 @@ static int PicoFrameSimple(void) } #else for (y=0;y<224;y++) PicoLine(y); +#endif #endif } else PicoFrameFull(); diff --git a/Pico/Pico.h b/Pico/Pico.h index 7e2ec691..73b7d40a 100644 --- a/Pico/Pico.h +++ b/Pico/Pico.h @@ -167,7 +167,6 @@ void vidConvCpyRGB565(void *to, void *from, int pixels); #define PDRAW_SONIC_MODE (1<<5) // mid-frame palette changes for 8bit renderer #define PDRAW_PLANE_HI_PRIO (1<<6) // have layer with all hi prio tiles (mk3) #define PDRAW_SHHI_DONE (1<<7) // layer sh/hi already processed -#define PDRAW_EARLY_BLANK (1<<8) // blanking enabled at the start of prev line extern int rendstatus; extern unsigned short HighPal[0x100]; diff --git a/Pico/PicoFrameHints.c b/Pico/PicoFrameHints.c index b224c9b7..2d0fbe26 100644 --- a/Pico/PicoFrameHints.c +++ b/Pico/PicoFrameHints.c @@ -73,7 +73,7 @@ static int PicoFrameHints(void) // This is to make active scan longer (needed for Double Dragon 2, mainly) CPUS_RUN(CYCLES_M68K_ASD, CYCLES_S68K_ASD); - for (y=0;yreg[1]&0x40) || y > 100) { - PicoFrameFull(); + // find the right moment for frame renderer, when display is no longer blanked + if ((pv->reg[1]&0x40) || y > 100) { + PicoFrameFull(); #ifdef DRAW_FINISH_FUNC - DRAW_FINISH_FUNC(); + DRAW_FINISH_FUNC(); #endif - skip = 1; - } - } - else - { -#if !CAN_HANDLE_240_LINES - if (y < 224) -#endif - PicoLine(y); + skip = 1; } } @@ -147,10 +138,14 @@ static int PicoFrameHints(void) #endif } -#ifdef DRAW_FINISH_FUNC if (!skip) + { + if (DrawScanline < y) + PicoDrawSync(y - 1, 0); +#ifdef DRAW_FINISH_FUNC DRAW_FINISH_FUNC(); #endif + } // V-int line (224 or 240) Pico.m.scanline=(short)y; @@ -218,7 +213,7 @@ static int PicoFrameHints(void) // PAL line count might actually be 313 according to Steve Snake, but that would complicate things. lines = Pico.m.pal ? 312 : 262; - for (y++;yreg[1]&0x40) && + !(!pvid->pending && + ((pvid->command & 0xc00000f0) == 0x40000010 && Pico.vsram[pvid->addr>>1] == d)) + ) + DrawSync(0); + if (pvid->pending) { CommandChange(); pvid->pending=0; @@ -344,7 +362,7 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d) else { // preliminary FIFO emulation for Chaos Engine, The (E) - if(!(pvid->status&8) && (pvid->reg[1]&0x40) && Pico.m.scanline!=-1 && !(PicoOpt&POPT_DIS_VDP_FIFO)) // active display, accurate mode? + if (!(pvid->status&8) && (pvid->reg[1]&0x40) && Pico.m.scanline!=-1 && !(PicoOpt&POPT_DIS_VDP_FIFO)) // active display, accurate mode? { pvid->status&=~0x200; // FIFO no longer empty pvid->lwrite_cnt++; @@ -362,8 +380,9 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d) if (a==0x04) // Control (command) port 4 or 6 { - if(pvid->pending) + if (pvid->pending) { + if (d & 0x80) DrawSync(0); // only need sync for DMA // Low word of command: pvid->command&=0xffff0000; pvid->command|=d; @@ -377,24 +396,26 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d) // Register write: int num=(d>>8)&0x1f; int dold=pvid->reg[num]; + int update_irq = 0, blank_on = 0; pvid->type=0; // register writes clear command (else no Sega logo in Golden Axe II) if (num > 0x0a && !(pvid->reg[1]&4)) { elprintf(EL_ANOMALY, "%02x written to reg %02x in SMS mode @ %06x", d, num, SekPc); return; - } else - pvid->reg[num]=(unsigned char)d; + } switch (num) { case 0x00: elprintf(EL_INTSW, "hint_onoff: %i->%i [%i] pend=%i @ %06x", (dold&0x10)>>4, (d&0x10)>>4, SekCyclesDone(), (pvid->pending_ints&0x10)>>4, SekPc); - goto update_irq; + update_irq = 1; + break; case 0x01: elprintf(EL_INTSW, "vint_onoff: %i->%i [%i] pend=%i @ %06x", (dold&0x20)>>5, (d&0x20)>>5, SekCyclesDone(), (pvid->pending_ints&0x20)>>5, SekPc); - if (!(d&0x40) && SekCyclesLeft > 390) rendstatus |= PDRAW_EARLY_BLANK; - goto update_irq; + if (!(d&0x40) && SekCyclesLeft > 390) blank_on = 1; + update_irq = 1; + break; case 0x05: if (d^dold) rendstatus |= PDRAW_SPRITES_MOVED; break; @@ -403,21 +424,19 @@ PICO_INTERNAL_ASM void PicoVideoWrite(unsigned int a,unsigned short d) if ((d^dold)&8) Pico.m.dirtyPal = 2; break; } - return; + DrawSync(blank_on); + pvid->reg[num]=(unsigned char)d; + if (!update_irq) return; -update_irq:; #ifndef EMU_CORE_DEBUG - // update IRQ level (Lemmings, Wiz 'n' Liz intro, ... ) - // may break if done improperly: - // International Superstar Soccer Deluxe (crash), Street Racer (logos), Burning Force (gfx), - // Fatal Rewind (crash), Sesame Street Counting Cafe + // update IRQ level if (!SekShouldInterrupt) // hack { int lines, pints, irq=0; lines = (pvid->reg[1] & 0x20) | (pvid->reg[0] & 0x10); pints = (pvid->pending_ints&lines); - if(pints & 0x20) irq = 6; - else if(pints & 0x10) irq = 4; + if (pints & 0x20) irq = 6; + else if (pints & 0x10) irq = 4; SekInterrupt(irq); // update line if (irq && Pico.m.scanline!=-1) SekEndRun(24); // make it delayed @@ -437,20 +456,17 @@ update_irq:; PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a) { - unsigned int d=0; - a&=0x1c; - if (a==0x00) // data port { - d=VideoRead(); - goto end; + return VideoRead(); } if (a==0x04) // control port { struct PicoVideo *pv=&Pico.video; + unsigned int d; d=pv->status; if (PicoOpt&POPT_ALT_RENDERER) d|=0x0020; // sprite collision (Shadow of the Beast) if (!(pv->reg[1]&0x40)) d|=0x0008; // set V-Blank if display is disabled @@ -462,7 +478,7 @@ PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a) pv->pending=0; // ctrl port reads clear write-pending flag (Charles MacDonald) elprintf(EL_SR, "SR read: %04x @ %06x", d, SekPc); - goto end; + return d; } // H-counter info (based on Generator): @@ -482,9 +498,10 @@ PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a) // check: Sonic 3D Blast bonus, Cannon Fodder, Chase HQ II, 3 Ninjas kick back, Road Rash 3, Skitchin', Wheel of Fortune if ((a&0x1c)==0x08) { - unsigned int hc; + unsigned int hc, d; - if(Pico.m.scanline != -1) { + if (Pico.m.scanline != -1) + { int lineCycles=(488-SekCyclesLeft)&0x1ff; d=Pico.m.scanline; // V-Counter @@ -500,9 +517,9 @@ PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a) } if(Pico.m.pal) { - if(d >= 0x103) d-=56; // based on Gens + if (d >= 0x103) d-=56; // based on Gens } else { - if(d >= 0xEB) d-=6; + if (d >= 0xEB) d-=6; } if((Pico.video.reg[12]&6) == 6) { @@ -514,10 +531,8 @@ PICO_INTERNAL_ASM unsigned int PicoVideoRead(unsigned int a) elprintf(EL_HVCNT, "hv: %02x %02x (%i) @ %06x", hc, d, SekCyclesDone(), SekPc); d&=0xff; d<<=8; d|=hc; - goto end; + return d; } -end: - - return d; + return 0; } diff --git a/Pico/sound/ym2612.c b/Pico/sound/ym2612.c index 59bb0cc8..56c363a1 100644 --- a/Pico/sound/ym2612.c +++ b/Pico/sound/ym2612.c @@ -1833,12 +1833,7 @@ int YM2612Write_(unsigned int a, unsigned int v) ret = OPNWriteReg(addr, v); break; } -/* - if(ret) { - extern int Scanline; - dprintf("ymw [%i]", Scanline); - } -*/ + return ret; } -- 2.39.5