gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Keeping it 60fps

#145715 - Rajveer - Tue Nov 20, 2007 9:21 pm

I have a menu which loads ships that the player can select, and (with everything else disabled) draws their icons along the bottom of the screen. The icons are moved along the screen as the user scrolls through the list. The location of the icons are stored in an array called icon_X which simply stores the icons x-coordinate, as all of its 4 corners can be worked out from that. When drawing 11 icons, the game runs at 60fps, running more makes it miss a VBlank and it runs at 30fps. The code is the following:

Code:
while(app_Controller == 2)
   {
      //Scan Input
      scanKeys();
      
// DRAW THE FADE POLYGON, SHIP, HUD AND ICONS:

      //Set Texture stack
      glMatrixMode(GL_TEXTURE);
      glLoadIdentity();
      
      //Set Projection stack (view) for fade (orthos)
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrthof32(0, 256, 0, 192, 0.1, 1000);
      
      //Set Modelview stack
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      
      //Fade In if menu_Controller is 0
      if(menu_Controller == 0)
      {
         //Draw a black quad with alpha set to fade variable, layer 1
         glPolyFmt(POLY_ALPHA(fade) | POLY_CULL_NONE | POLY_ID(2));
         
         glBegin(GL_QUAD);
         
         glColor3b(0,0,0);
         glVertex3v16(0, -65, -1);
         glVertex3v16(0, 193, -1);
         glVertex3v16(257, 193, -1);
         glVertex3v16(257, -65, -1);
      
         glEnd();
         
         //Reduce alpha of black quad, check if fade has completed
         fade -= 1;
         if(fade <= 0)
         {
            fade = 0;
            menu_Controller = 1;
         }
      }
      
      //Check input, move elements, change 3D model if menu_Controller is 1
      else if(menu_Controller == 1)
      {
           //Check for left/right
         if(keysDown() & KEY_RIGHT)
         {
            timer_Left = 0;
            timer_Held = 0;
            ship_Current++;
         }
         else if(keysDown() & KEY_LEFT)
         {
            timer_Left = 0;
            timer_Held = 0;
            ship_Current--;
         }
         else if(keysHeld() & KEY_RIGHT)
         {
            timer_Left = 0;
            timer_Held++;
            if(timer_Held > 9)
            {
               timer_Ship++;
               if(timer_Ship > 3)
               {
                  timer_Ship = 0;
                  ship_Current++;
               }
            }
         }
         else if(keysHeld() & KEY_LEFT)
         {
            timer_Left = 0;
            timer_Held++;
            if(timer_Held > 9)
            {
               timer_Ship++;
               if(timer_Ship > 3)
               {
                  timer_Ship = 0;
                  ship_Current--;
               }
            }
         }

         else if(!keysDown() && !keysHeld())
         {
            timer_Left++;
            timer_Ship = 0;
            timer_Held = 0;
         }
         
         if(ship_Current > (ship_Number - 1))
         {ship_Current = (ship_Number - 1);}
         else if(ship_Current < 0)
         {ship_Current = 0;}
               
         //Check if current ship is in middle, if not move all icons till correct one is in middle
         if(icon_X[ship_Current] > 112)
         {
            for(temp_Counter = 0; temp_Counter < ship_Number; temp_Counter++)
            {
               icon_X[temp_Counter] -= 8;
            }   
         }
         else if(icon_X[ship_Current] < 112)
         {
            for(temp_Counter = 0; temp_Counter < ship_Number; temp_Counter++)
            {
               icon_X[temp_Counter] += 8;
            }   
         }
         else
         {
            if(!keysDown() && !keysHeld())
            {
               if(ship_Current_Loaded != ship_Current)
               {
                  if(timer_Left > 8)
                  {
                     //Retrieve current address of texture and texture palette, unload ship, load new ship
                     //whilst loading new texture and texture palette into correct address
                     ObjReloadShip(ships[ship_Current].folder_Name, loaded_Ship, 1, 1, 1);
                     ship_Current_Loaded = ship_Current;                     
                  }
               }   
            }
         }   
         
         if(keysDown() & KEY_A)
         {
            menu_Controller = 2;
         }   
      }
      
// DRAW THE SELECTED SHIP (PERSPECTIVE):
     //DISABLED!!

// DRAW THE HUD AND ICONS (ORTHOGRAPHIC):
   //DISABLED!!
      
      //Set viewport for whole screen
      glViewport(0,0,255,191); //Viewport is changed when drawing the ship too, so is called twice usually
      
      //Draw the HUD, layer 4
      //Set Texture stack
      glMatrixMode(GL_TEXTURE);
      glLoadIdentity();
      
      //Set Projection stack (view) for the HUD
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      glOrthof32(0, 256, 0, 192, 0.1, 1000);
      
      //Set Modelview stack
      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();
      
      //Draw Icons, layer 3
      for(temp_Counter = 0; temp_Counter < ship_Number; temp_Counter++)
      {
         glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE | POLY_ID(2));
         glBindTexture(GL_TEXTURE_2D, texture_Icon[temp_Counter]);
         glColorTable(GL_RGB16, texture_Icon_Palette[temp_Counter]);
               
         glBegin(GL_QUAD);
         
         glColor3b(255,255,255);
         glTexCoord2t16(0,512);
         glVertex3v16(icon_X[temp_Counter], 0, -3);
         glTexCoord2t16(0,0);
         glVertex3v16(icon_X[temp_Counter], 32, -3);
         glTexCoord2t16(512,0);
         glVertex3v16(icon_X[temp_Counter] + 32, 32, -3);
         glTexCoord2t16(512,512);
         glVertex3v16(icon_X[temp_Counter] + 32, 0, -3);
         
         glEnd();
         glBindTexture(0, 0);
      }
      
        swiWaitForVBlank();
      GFX_FLUSH = 0;
}


Should the code, along with repeating drawing the icons 11 times at the end and modifying the icons x-coordinate if the right one isn't in the middle, be capped at 30fps? What can I change/what am I doing wrong??

P.S. Obviously the situation worsens when actually drawing the 3D models and HUD icons, but that's all disabled and that's probably because I'm not using display lists with the models (going through an array of triangles, which links to arrays of vertices, normals, texture coords).
P.P.S. I've cut out some menu loading code before the first while loop i.e. loading ship models, icons, filling the icon_X array e.t.c.

#145716 - Mighty Max - Tue Nov 20, 2007 9:43 pm

GFX_FLUSH = x

is not executed before the next vblank. Since you are calling it just after the vblank you are wasting a frame each time
_________________
GBAMP Multiboot

#145728 - Rajveer - Wed Nov 21, 2007 1:19 am

So the code I posted takes more than a frame to process? That seems a bit weird, it's not doing that much I would have thought, modifying some variables and drawing a few quads. Can anybody find where my code may be slowing down? (I can spot some bad coding but nothing that should have this much of an effect)

#145730 - tepples - Wed Nov 21, 2007 1:47 am

Profile your code.

The quick and dirty way to do this is to play with the palette or the enabled backgrounds after drawing each object. This allows you to see the time each step takes as the thickness of a bar across the screen. Thinner bar == faster code.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#145734 - wintermute - Wed Nov 21, 2007 4:09 am

Rajveer wrote:
So the code I posted takes more than a frame to process? That seems a bit weird, it's not doing that much I would have thought, modifying some variables and drawing a few quads. Can anybody find where my code may be slowing down? (I can spot some bad coding but nothing that should have this much of an effect)


No, he's saying that the write to GFX_FLUSH effectively causes a second wait for vblank when you start to fill the geometry pipeline again since the buffer swap isn't completed until the vblank period following the write.

Try placing the GFX_FLUSH = 0; *before* the swiWaitForVBlank();

On hardware the swi will have effectively no effect since the processor gets stalled until buffer swap completion when it tries to write more geometry data. As far as I can tell this behaviour is not emulated on any of the popular DS emulators, including no$gba ( up to 2.5b at least, I haven't tested on the just released 2.5c as yet)
_________________
devkitPro - professional toolchains at amateur prices
devkitPro IRC support
Personal Blog

#145749 - Rajveer - Wed Nov 21, 2007 2:08 pm

Ahhah! Cheers for that guys, it works fine now. Funny thing is that I never picked up on that bug and I always wondered why my demos and projects only run at 30fps, haha.