diff options
author | Arisotura <thetotalworm@gmail.com> | 2019-06-10 03:05:26 +0200 |
---|---|---|
committer | Arisotura <thetotalworm@gmail.com> | 2019-06-10 03:05:26 +0200 |
commit | d28035674a7a886199f1fb5805fdd6e8238215d9 (patch) | |
tree | f3f72cf93d442559690ee3d03e2f8058bcaf23c4 | |
parent | 9ab331c6dd9ade3c0c2850ebb69b8306e8c71401 (diff) |
GPU2D: hardware renders sprites one scanline in advance.
fixes #375 (midframe OAM update)
-rw-r--r-- | src/GPU.cpp | 12 | ||||
-rw-r--r-- | src/GPU2D.cpp | 159 | ||||
-rw-r--r-- | src/GPU2D.h | 10 |
3 files changed, 62 insertions, 119 deletions
diff --git a/src/GPU.cpp b/src/GPU.cpp index 3ec223c..dcd79b4 100644 --- a/src/GPU.cpp +++ b/src/GPU.cpp @@ -871,12 +871,24 @@ void StartHBlank(u32 line) GPU2D_B->DrawScanline(line); } + // sprites are pre-rendered one scanline in advance + if (line < 191) + { + GPU2D_A->DrawSprites(line+1); + GPU2D_B->DrawSprites(line+1); + } + NDS::CheckDMAs(0, 0x02); } else if (VCount == 215) { GPU3D::VCount215(); } + else if (VCount == 262) + { + GPU2D_A->DrawSprites(0); + GPU2D_B->DrawSprites(0); + } if (DispStat[0] & (1<<4)) NDS::SetIRQ(0, NDS::IRQ_HBlank); if (DispStat[1] & (1<<4)) NDS::SetIRQ(1, NDS::IRQ_HBlank); diff --git a/src/GPU2D.cpp b/src/GPU2D.cpp index 8823d1b..e0da772 100644 --- a/src/GPU2D.cpp +++ b/src/GPU2D.cpp @@ -1218,10 +1218,14 @@ void GPU2D::CalculateWindowMask(u32 line) for (u32 i = 0; i < 256; i++) WindowMask[i] = WinCnt[2]; // window outside - if ((DispCnt & (1<<15)) && (DispCnt & (1<<12))) + if (DispCnt & (1<<15)) { // OBJ window - DrawSpritesWindow(line); + for (int i = 0; i < 256; i++) + { + if (OBJWindow[i]) + WindowMask[i] = WinCnt[3]; + } } if (DispCnt & (1<<14)) @@ -1257,7 +1261,7 @@ void GPU2D::CalculateWindowMask(u32 line) template<u32 bgmode> -void GPU2D::DrawScanlineBGMode(u32 line, u32 nsprites) +void GPU2D::DrawScanlineBGMode(u32 line) { for (int i = 3; i >= 0; i--) { @@ -1302,12 +1306,12 @@ void GPU2D::DrawScanlineBGMode(u32 line, u32 nsprites) DrawBG_Text(line, 0); } } - if ((DispCnt & 0x1000) && nsprites) + if ((DispCnt & 0x1000) && NumSprites) InterleaveSprites(0x8000 | (i<<16)); } } -void GPU2D::DrawScanlineBGMode6(u32 line, u32 nsprites) +void GPU2D::DrawScanlineBGMode6(u32 line) { if (Num) { @@ -1332,7 +1336,7 @@ void GPU2D::DrawScanlineBGMode6(u32 line, u32 nsprites) DrawBG_3D(); } } - if ((DispCnt & 0x1000) && nsprites) + if ((DispCnt & 0x1000) && NumSprites) InterleaveSprites(0x8000 | (i<<16)); } } @@ -1360,21 +1364,16 @@ void GPU2D::DrawScanline_BGOBJ(u32 line) else memset(WindowMask, 0xFF, 256); - // prerender sprites - u32 nsprites = 0; - memset(OBJLine, 0, 256*4); - if (DispCnt & 0x1000) nsprites = DrawSprites(line); - // TODO: what happens in mode 7? mode 6 on the sub engine? switch (DispCnt & 0x7) { - case 0: DrawScanlineBGMode<0>(line, nsprites); break; - case 1: DrawScanlineBGMode<1>(line, nsprites); break; - case 2: DrawScanlineBGMode<2>(line, nsprites); break; - case 3: DrawScanlineBGMode<3>(line, nsprites); break; - case 4: DrawScanlineBGMode<4>(line, nsprites); break; - case 5: DrawScanlineBGMode<5>(line, nsprites); break; - case 6: DrawScanlineBGMode6(line, nsprites); break; + case 0: DrawScanlineBGMode<0>(line); break; + case 1: DrawScanlineBGMode<1>(line); break; + case 2: DrawScanlineBGMode<2>(line); break; + case 3: DrawScanlineBGMode<3>(line); break; + case 4: DrawScanlineBGMode<4>(line); break; + case 5: DrawScanlineBGMode<5>(line); break; + case 6: DrawScanlineBGMode6(line); break; } // color special effects @@ -2124,8 +2123,13 @@ void GPU2D::InterleaveSprites(u32 prio) } } -u32 GPU2D::DrawSprites(u32 line) +void GPU2D::DrawSprites(u32 line) { + NumSprites = 0; + memset(OBJLine, 0, 256*4); + memset(OBJWindow, 0, 256); + if (!(DispCnt & 0x1000)) return; + u16* oam = (u16*)&GPU::OAM[Num ? 0x400 : 0]; const s32 spritewidth[16] = @@ -2154,8 +2158,7 @@ u32 GPU2D::DrawSprites(u32 line) if ((attrib[2] & 0x0C00) != bgnum) continue; - if (((attrib[0] >> 10) & 0x3) == 2) - continue; + bool iswin = (((attrib[0] >> 10) & 0x3) == 2); if (attrib[0] & 0x0100) { @@ -2182,8 +2185,12 @@ u32 GPU2D::DrawSprites(u32 line) u32 rotparamgroup = (attrib[1] >> 9) & 0x1F; - DrawSprite_Rotscale<false>(attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos); - nsprites++; + if (iswin) + DrawSprite_Rotscale<true>(attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos); + else + DrawSprite_Rotscale<false>(attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos); + + NumSprites++; } else { @@ -2207,91 +2214,13 @@ u32 GPU2D::DrawSprites(u32 line) if (attrib[1] & 0x2000) ypos = height-1 - ypos; - DrawSprite_Normal<false>(attrib, width, xpos, ypos); - nsprites++; - } - } - } - - return nsprites; -} - -void GPU2D::DrawSpritesWindow(u32 line) -{ - u16* oam = (u16*)&GPU::OAM[Num ? 0x400 : 0]; - - const s32 spritewidth[16] = - { - 8, 16, 8, 0, - 16, 32, 8, 0, - 32, 32, 16, 0, - 64, 64, 32, 0 - }; - const s32 spriteheight[16] = - { - 8, 8, 16, 0, - 16, 8, 32, 0, - 32, 16, 32, 0, - 64, 32, 64, 0 - }; - - for (int sprnum = 127; sprnum >= 0; sprnum--) - { - u16* attrib = &oam[sprnum*4]; - - if (((attrib[0] >> 10) & 0x3) != 2) - continue; - - if (attrib[0] & 0x0100) - { - u32 sizeparam = (attrib[0] >> 14) | ((attrib[1] & 0xC000) >> 12); - s32 width = spritewidth[sizeparam]; - s32 height = spriteheight[sizeparam]; - s32 boundwidth = width; - s32 boundheight = height; + if (iswin) + DrawSprite_Normal<true>(attrib, width, xpos, ypos); + else + DrawSprite_Normal<false>(attrib, width, xpos, ypos); - if (attrib[0] & 0x0200) - { - boundwidth <<= 1; - boundheight <<= 1; + NumSprites++; } - - u32 ypos = attrib[0] & 0xFF; - ypos = (line - ypos) & 0xFF; - if (ypos >= (u32)boundheight) - continue; - - s32 xpos = (s32)(attrib[1] << 23) >> 23; - if (xpos <= -boundwidth) - continue; - - u32 rotparamgroup = (attrib[1] >> 9) & 0x1F; - - DrawSprite_Rotscale<true>(attrib, &oam[(rotparamgroup*16) + 3], boundwidth, boundheight, width, height, xpos, ypos); - } - else - { - if (attrib[0] & 0x0200) - continue; - - u32 sizeparam = (attrib[0] >> 14) | ((attrib[1] & 0xC000) >> 12); - s32 width = spritewidth[sizeparam]; - s32 height = spriteheight[sizeparam]; - - u32 ypos = attrib[0] & 0xFF; - ypos = (line - ypos) & 0xFF; - if (ypos >= (u32)height) - continue; - - s32 xpos = (s32)(attrib[1] << 23) >> 23; - if (xpos <= -width) - continue; - - // yflip - if (attrib[1] & 0x2000) - ypos = height-1 - ypos; - - DrawSprite_Normal<true>(attrib, width, xpos, ypos); } } } @@ -2399,7 +2328,7 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 if (color & 0x8000) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = color | prio; } } @@ -2463,7 +2392,7 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 if (color) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = pal[color] | prio; } } @@ -2521,7 +2450,7 @@ void GPU2D::DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 if (color) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = pal[color] | prio; } } @@ -2635,7 +2564,7 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos) if (color & 0x8000) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = color | prio; } @@ -2662,7 +2591,7 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos) if (color & 0x8000) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = color | prio; } @@ -2722,7 +2651,7 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos) if (color) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = pal[color] | prio; } @@ -2751,7 +2680,7 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos) if (color) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = pal[color] | prio; } @@ -2800,7 +2729,7 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos) if (color) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = pal[color] | prio; } @@ -2834,7 +2763,7 @@ void GPU2D::DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos) if (color) { - if (window) WindowMask[xpos] = WinCnt[3]; + if (window) OBJWindow[xpos] = 1; else OBJLine[xpos] = pal[color] | prio; } diff --git a/src/GPU2D.h b/src/GPU2D.h index 57436c7..b9a2422 100644 --- a/src/GPU2D.h +++ b/src/GPU2D.h @@ -53,6 +53,7 @@ public: void SampleFIFO(u32 offset, u32 num); void DrawScanline(u32 line); + void DrawSprites(u32 line); void VBlank(); void VBlankEnd(); @@ -76,6 +77,9 @@ private: u8 WindowMask[256] __attribute__((aligned (8))); u32 OBJLine[256] __attribute__((aligned (8))); + u8 OBJWindow[256] __attribute__((aligned (8))); + + u32 NumSprites; u16 DispFIFO[16]; u32 DispFIFOReadPtr; @@ -129,8 +133,8 @@ private: u32 ColorBrightnessDown(u32 val, u32 factor); u32 ColorComposite(int i, u32 val1, u32 val2); - template<u32 bgmode> void DrawScanlineBGMode(u32 line, u32 nsprites); - void DrawScanlineBGMode6(u32 line, u32 nsprites); + template<u32 bgmode> void DrawScanlineBGMode(u32 line); + void DrawScanlineBGMode6(u32 line); void DrawScanline_BGOBJ(u32 line); static void DrawPixel_Normal(u32* dst, u16 color, u32 flag); @@ -144,8 +148,6 @@ private: void DrawBG_Large(u32 line); void InterleaveSprites(u32 prio); - u32 DrawSprites(u32 line); - void DrawSpritesWindow(u32 line); template<bool window> void DrawSprite_Rotscale(u16* attrib, u16* rotparams, u32 boundwidth, u32 boundheight, u32 width, u32 height, s32 xpos, s32 ypos); template<bool window> void DrawSprite_Normal(u16* attrib, u32 width, s32 xpos, s32 ypos); |