aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArisotura <thetotalworm@gmail.com>2019-06-10 03:05:26 +0200
committerArisotura <thetotalworm@gmail.com>2019-06-10 03:05:26 +0200
commitd28035674a7a886199f1fb5805fdd6e8238215d9 (patch)
treef3f72cf93d442559690ee3d03e2f8058bcaf23c4
parent9ab331c6dd9ade3c0c2850ebb69b8306e8c71401 (diff)
GPU2D: hardware renders sprites one scanline in advance.
fixes #375 (midframe OAM update)
-rw-r--r--src/GPU.cpp12
-rw-r--r--src/GPU2D.cpp159
-rw-r--r--src/GPU2D.h10
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);