But I have a problem: calls to the MP3 player take much more than 1/60th of a second so I can't animate the UI properly. I've tried to modify the MP3 decoder to decode smaller chunks at a time so it can keep up with the UI but no luck. Probably because doing things in smaller chunks makes the cache less effective.
So I thought of leaving the MP3 code on main() and update the UI in the Vblank IRQ handler. Here's what my code looks like right now (showing only the relevant stuff):
Code: Select all
int inputKeysDown;
int inputKeysHeld;
int inputKeysRepeat;
touchPosition inputTouch;
stack<Scene*> scenes;
void vBlank()
{
if(scenes.size() == 0)
{
fprintf(stderr, "[IRQ] No scene found!\n");
return;
}
timerStart(2, ClockDivider_256, 0, NULL);
fprintf(stderr, "[IRQ] entering\n");
bgUpdate();
scanKeys();
touchRead(&inputTouch);
inputKeysDown = keysDown();
inputKeysHeld= keysHeld();
inputKeysRepeat = keysDownRepeat();
Scene* sc = scenes.top();
sc->tick();
sc->render();
//Draw BG image
setTexture(0);
glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE);
GFX_COLOR = RGB15(31, 31, 31);
glBegin(GL_QUAD);
GFX_TEX_COORD = (TEXTURE_PACK(inttot16(0), inttot16(0)));
glVertex3v16(0, 0, -600 );
GFX_TEX_COORD = (TEXTURE_PACK(inttot16(256), inttot16(0)));
glVertex3v16(256, 0, -600 );
GFX_TEX_COORD = (TEXTURE_PACK(inttot16(256), inttot16(192)));
glVertex3v16(256, 192, -600 );
GFX_TEX_COORD = (TEXTURE_PACK(inttot16(0), inttot16(192)));
glVertex3v16(0, 192, -600 );
glEnd();
glFlush(GL_TRANS_MANUALSORT);
//2181 = TIMER_HZ / 256 / 60 = Number of time ticks occurring in 1/60th second
int dd = timerTick(2)*100/2181;
printf("\x1b[11;1HCPU_IRQ: %d %% ", dd);
printf("\x1b[13;1H3D Scanline Buffer: %d ", (*(vu32*) 0x04000320) );
printf("\x1b[14;1HVertex RAM: %d ", GFX_VERTEX_RAM_USAGE);
printf("\x1b[15;1HPolygon RAM: %d ", GFX_POLYGON_RAM_USAGE);
struct mallinfo inf = mallinfo();
printf("\x1b[8;1HRAM %d ", inf.uordblks);
fprintf(stderr, "[IRQ] exiting\n");
fprintf(stderr, "[IRQ] Total time %d\n", dd);
timerStop(2);
}
int main(int argc, char *argv[])
{
(...)
irqSet(IRQ_VBLANK, vBlank);
irqEnable(IRQ_VBLANK);
while(true)
{
if(globalPlayer)
globalPlayer->update();
(...)
swiWaitForVBlank();
}
return 0;
}
It measures CPU related to the 60Hz screen refresh rate: 100% would mean it's taking exactly 1/60th of a second. Usually it is at CPU 2%. When you scroll the list and it has to render some files it goes up to 30% or so.
BUT There's ONE issue: Sometimes the CPU *can* go up to 100% (for example scrolling the list really quickly). Then everything stops working.
The IRQ handler is still called every frame, but it now takes more or less 95% CPU always, even if the list is not being scrolled. It "locks up" at 95% CPU. Also, the touch screen stops working for some reason. I can still navigate the list using the arrow keys though. And of course, since now IRQ mode takes up 95% CPU there's no CPU time left for the MP3 decoder and it hangs too
This bug is present both in DeSmuME and the real DS.
I think I know why it happens: I'm calling glFlush. According to GBATek, glFlush locks up until next Vblank. If I remove the glFlush call it doesnt lock up. Probably if the CPU goes too high, glFlush is called too late and it waits for the *next* Vblank. Then the previous Vblank IRQ is called late too, which makes the next glFlush wait for the *next* vblank again
So, how can I prevent this from happening? Is there a reliable way to do this?