GPU2D: hardware renders sprites one scanline in advance.
fixes #375 (midframe OAM update)
This commit is contained in:
parent
9ab331c6dd
commit
d28035674a
12
src/GPU.cpp
12
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);
|
||||
|
|
161
src/GPU2D.cpp
161
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,93 +2214,15 @@ u32 GPU2D::DrawSprites(u32 line)
|
|||
if (attrib[1] & 0x2000)
|
||||
ypos = height-1 - ypos;
|
||||
|
||||
DrawSprite_Normal<false>(attrib, width, xpos, ypos);
|
||||
nsprites++;
|
||||
if (iswin)
|
||||
DrawSprite_Normal<true>(attrib, width, xpos, ypos);
|
||||
else
|
||||
DrawSprite_Normal<false>(attrib, width, xpos, ypos);
|
||||
|
||||
NumSprites++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 (attrib[0] & 0x0200)
|
||||
{
|
||||
boundwidth <<= 1;
|
||||
boundheight <<= 1;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<bool window>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
10
src/GPU2D.h
10
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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue