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.

Coding > Double Buffering - Determining what surface to draw on

#10771 - Ruiner - Mon Sep 15, 2003 6:48 am

I have a few title screens at the beginning of my game giving credits where due. On the first flip it works and it doesn't on the second.

I'm guessing the reason this doesn't work is because its not actually switching the backbuffer pointer to whatever surface is actually in back. Can anyone verify this for me? Flip writes the backbuffer to the front no matter what REG_DISPCNT equals so I assumed I could just blast data to the back every time.

Code:

void DMA3Copy(u16* _source, u16* _dest, u32 _wordCount, u32 _mode)
{
   REG_DM3SAD = (u32)_source;
   REG_DM3DAD = (u32)_dest;
   REG_DM3CNT = _wordCount | _mode;
}

void Flip()
{
   if (REG_DISPCNT & BACKBUFFER)
   {
      REG_DISPCNT &= ~BACKBUFFER;
      VideoBuffer = BackBuffer;
   }
   else
   {
      REG_DISPCNT |= BACKBUFFER;
      VideoBuffer = BackBuffer;
   }
}

void DisplaySplash(const u16* _palette, const u16* _data)
{
    DMA3Copy(const_cast <u16*> (_palette), BGPaletteMem, 256, DMA_16NOW);
    DMA3Copy(const_cast <u16*> (_data), BackBuffer, 19200, DMA_16NOW);
   WaitForVblank();
   Flip();

   while(1)
   {
      key_refresh();
      for(u16 i = 0; i < 10; i++)
         if(release[i])
            return;
   }
}


Also Im not entirely sure whats going on there. Should VideoBuffer = BackBuffer possibly be DMA'd or is that just swapping pointer addresses?

#10772 - DekuTree64 - Mon Sep 15, 2003 7:02 am

You should set VideoBuffer to 0x6000000 when BACKBUFFER is set, and 0x600A000 when it's unset. That way, you're drawing to the buffer that's not curren't being shown. You shouldn't have to copy anything when using hardware double-buffering, that's why it's so good to have.
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#10775 - Ruiner - Mon Sep 15, 2003 7:14 am

So something to the effect of:

Code:

void Flip()
{
   if (REG_DISPCNT & BACKBUFFER)
   {
      REG_DISPCNT &= ~BACKBUFFER;
      VideoBuffer = BackBuffer;
      BackBuffer = (u16*)0x600A000;
   }
   else
   {
      REG_DISPCNT |= BACKBUFFER;
      VideoBuffer = BackBuffer;
      BackBuffer = (u16*)0x6000000;
   }
}


right?

#10790 - Quirky - Mon Sep 15, 2003 7:42 pm

I have this code and I always draw to the array "theBackBuffer". swapBank gets called at the end of every frame.

Code:

#define VideoBuffer    (( volatile u16*)0x6000000)
#define BackBuffer    (( volatile u16*)0x600A000)
volatile u16* theBackBuffer = BackBuffer;
void swapBank(void) {
 
  if (REG_DISPCNT & BACKBUFFER)
  {
    REG_DISPCNT &= ~BACKBUFFER;
    theBackBuffer = BackBuffer;
  }
  else
  {
    REG_DISPCNT |= BACKBUFFER;
    theBackBuffer = VideoBuffer;
  }
}



However that is badly named, as the technique in the GBA isn't back buffering at all, it is page flipping. When you have the relevent bit set in REG_DISPCNT the screen refresheses itself from the data at 600A000, when the bit is not set in the register, the screen refreshes from 6000000.

If it were a true buffer then the data from 600A000 would be copied to 6000000 and the screen would always read from 6000000.

#10795 - Ruiner - Tue Sep 16, 2003 12:45 am

Quirky thanks for the response. That one works to. I tried using the flip I posted above and that also works but I prefer swapping the pointer address like you did. Thanks