Double Buffering question

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
casual otaku
Posts: 3
Joined: Wed Dec 14, 2005 4:53 am

Double Buffering question

Post by casual otaku »

Hi,

I have created a simple program that lets the user control a character on the screen. At the moment all screen output is very flickery, I'm guessing that I have to implement double buffering but am not sure how to do this? My code is below:

Code: Select all

#include <pspdisplay.h>
#include <pspctrl.h>
#include <pspkernel.h>
#include <pspdebug.h>

PSP_MODULE_INFO&#40;"Character", 0, 1, 1&#41;;

SceCtrlData pad;

int x = 20, y = 20; // &#40;0,0&#41; denotes top left corner of PSP screen

/* Exit callback */
int exit_callback&#40;int arg1, int arg2, void *common&#41; 
&#123;
  sceKernelExitGame&#40;&#41;;
  return 0;
&#125;



/* Callback thread */
int CallbackThread&#40;SceSize args, void *argp&#41; 
&#123;
  int cbid;

  cbid = sceKernelCreateCallback&#40;"Exit Callback", exit_callback, NULL&#41;;
  sceKernelRegisterExitCallback&#40;cbid&#41;;

  sceKernelSleepThreadCB&#40;&#41;;

  return 0;
&#125;


/* Sets up the callback thread and returns its thread id */
int SetupCallbacks&#40;void&#41; 
&#123;
  int thid = 0;

  thid = sceKernelCreateThread&#40;"update_thread", CallbackThread, 0x11, 0xFA0, 0, 0&#41;;
  
  if&#40;thid >= 0&#41;
  &#123;
    sceKernelStartThread&#40;thid, 0, 0&#41;;
  &#125;

  return thid;
&#125;



void drawCharacter&#40;&#41;
&#123;
  pspDebugScreenClear&#40;&#41;;
  
  pspDebugScreenSetXY&#40;x, y&#41;;  
  pspDebugScreenPrintf&#40;"O"&#41;;   // character that the user controls    
&#125;



void inputLoop&#40;&#41;
&#123;
  while &#40;1&#41;
  &#123;
    pspDebugScreenSetXY&#40;0, 0&#41;;
    pspDebugScreenPrintf&#40;"Press X, O, &#91;&#93; or /\\ to move character... \n"&#41;;
    
    sceCtrlReadBufferPositive&#40;&pad, 1&#41;;
    
    if&#40;&#40;pad.Buttons&#41; & &#40;PSP_CTRL_CROSS&#41;&#41; // move down
    &#123;
      y++;  
      drawCharacter&#40;&#41;;
    &#125;
    else if&#40;&#40;pad.Buttons&#41; & &#40;PSP_CTRL_SQUARE&#41;&#41; // move left
    &#123;
      x--;
      drawCharacter&#40;&#41;;
    &#125;
    else if&#40;&#40;pad.Buttons&#41; & &#40;PSP_CTRL_TRIANGLE&#41;&#41; // move up
    &#123;
      y--;     
      drawCharacter&#40;&#41;;
    &#125;
    else if&#40;&#40;pad.Buttons&#41; & &#40;PSP_CTRL_CIRCLE&#41;&#41; // move down
    &#123;
      x++;     
      drawCharacter&#40;&#41;;
    &#125;
  &#125;     
&#125;



int main&#40;&#41;
&#123;
  pspDebugScreenInit&#40;&#41;;  
  SetupCallbacks&#40;&#41;;
  
  pspDebugScreenSetXY&#40;x, y&#41;; // initialise to x, y
  
  inputLoop&#40;&#41;;
  
  return 0;
&#125;
Brunni
Posts: 186
Joined: Sat Oct 08, 2005 10:27 pm

Post by Brunni »

It seems like you can't use double buffering with the standard console (you need to write your own text routines, rendered on a backbuffer). But you should at least wait the VBlank in your main loop, like this:

Code: Select all

void inputLoop&#40;&#41; 
&#123; 
  while &#40;1&#41; 
  &#123; 
    pspDebugScreenSetXY&#40;0, 0&#41;; 
    pspDebugScreenPrintf&#40;"Press X, O, &#91;&#93; or /\\ to move character... \n"&#41;; 
    
    sceCtrlReadBufferPositive&#40;&pad, 1&#41;; 
    
    if&#40;&#40;pad.Buttons&#41; & &#40;PSP_CTRL_CROSS&#41;&#41; // move down 
    &#123; 
      y++;  
      drawCharacter&#40;&#41;; 
    &#125; 
    else if&#40;&#40;pad.Buttons&#41; & &#40;PSP_CTRL_SQUARE&#41;&#41; // move left 
    &#123; 
      x--; 
      drawCharacter&#40;&#41;; 
    &#125; 
    else if&#40;&#40;pad.Buttons&#41; & &#40;PSP_CTRL_TRIANGLE&#41;&#41; // move up 
    &#123; 
      y--;      
      drawCharacter&#40;&#41;; 
    &#125; 
    else if&#40;&#40;pad.Buttons&#41; & &#40;PSP_CTRL_CIRCLE&#41;&#41; // move down 
    &#123; 
      x++;      
      drawCharacter&#40;&#41;; 
    &#125; 
    sceDisplayWaitVblankStart&#40;&#41;;
  &#125;      
&#125;
Also, I don't think it's a good idea to redraw the character one time in each 'if' in your loop, because it will become more and more complex as your game becomes bigger. For example, you could save its coordinates and compare them with those of the last time and redraw it only if they have changed...
Sorry for my bad english
Image Oldschool library for PSP - PC version released
dr_watson
Posts: 42
Joined: Mon Nov 28, 2005 11:30 am

Post by dr_watson »

Guess you're blitting your images by writing to VRAM directly? This is how I did double buffering:

Code: Select all

int main&#40;&#41;
&#123; 
	SceCtrlData pad;
	struct timeval tick;
	
	unsigned int oldButtons = 0;

	pBufferPointer&#91;0&#93; = &#40;u32*&#41;&#40;0x04000000+0x40000000&#41;;						// pointer to 1st page in VRAM
	pBufferPointer&#91;1&#93; = &#40;u32*&#41;&#40;0x04000000+0x40000000+FRAME_BUFFER_SIZE&#41;;	// pointer to 2nd page in VRAM

	pspDebugScreenInit&#40;&#41;;	// do this so that we can use pspDebugScreenPrintf
	SetupCallbacks&#40;&#41;; 
	
	sceCtrlSetSamplingCycle&#40;0&#41;;
	sceCtrlSetSamplingMode&#40;PSP_CTRL_MODE_ANALOG&#41;;
	
	sceDisplaySetMode&#40;0, SCREEN_WIDTH, SCREEN_HEIGHT&#41;;	

	bg = LoadImage&#40;"bg.png"&#41;;			// load bg
	mario = LoadImage&#40;"m.png"&#41;;			// load our character
	cursor = LoadImage&#40;"cursor.png"&#41;;	// load a cursor

	currentPage = 1;							// prepare a page to be displayed
	pVRAM = pBufferPointer&#91;currentPage&#93;;
	
	Render&#40;&#41;;									// render to page 1
	
	
	int lastTime = Sys_Milliseconds&#40;&#41;;

	while &#40;!done&#41;
	&#123;
		int timeNow = Sys_Milliseconds&#40;&#41;;
		int delta = timeNow-lastTime;
		lastTime = timeNow;

		offset--;					// change the offset position to draw the background image
		if &#40;offset<=-128&#41;			// this will give us an illusion of a moving background
			offset = 0;
		
		gettimeofday&#40;&tick, 0&#41;;

    	sceCtrlPeekBufferPositive&#40;&pad, 1&#41;;		// using sceCtrlPeekBufferPositive is faster than sceCtrlReadBufferPositive
												// because sceCtrlReadBufferPositive waits for vsync

		if &#40;pad.Buttons != 0&#41;					// one or more buttons have been pressed
		&#123;
			// do a screen shot only if CIRCLE button wasn't in 'down' state previously
			if &#40;&#40;pad.Buttons&PSP_CTRL_CIRCLE&#41; && !&#40;oldButtons&PSP_CTRL_CIRCLE&#41;&#41;	
			&#123;
				ScreenShot&#40;"ms0&#58;/screenshot.png"&#41;;
			&#125;

			// CROSS button to exit
			if &#40;pad.Buttons & PSP_CTRL_CROSS&#41;
			&#123;
				done = true;
			&#125;
   
			if &#40;pad.Buttons & PSP_CTRL_LEFT&#41;
			&#123;
				if &#40;xMan > 0&#41; xMan--;
			&#125;
			else if &#40;pad.Buttons & PSP_CTRL_RIGHT&#41;
			&#123;
				if &#40;xMan < SCREEN_WIDTH-1&#41; xMan++;
			&#125;
			
		&#125;
		
		oldButtons = pad.Buttons;
		
		// range of pad.Lx and pad.Ly is 0-255
		if &#40;pad.Lx<64&#41;
		&#123;
			if &#40;x>0&#41; x--;
		&#125;
		else if &#40;pad.Lx>196&#41;
		&#123;
			if &#40;x<SCREEN_WIDTH-1&#41;
				x++;
		&#125;
		if &#40;pad.Ly<64&#41;
		&#123;
			if &#40;y>0&#41; y--;
		&#125;
		else if &#40;pad.Ly>196&#41;
		&#123;
			if &#40;y<SCREEN_HEIGHT-1&#41;
				y++;
		&#125;

		// flip and bring the background page to the front
		sceDisplayWaitVblankStart&#40;&#41;;
		sceDisplaySetFrameBuf&#40;pVRAM, FRAME_BUFFER_WIDTH, PSP_DISPLAY_PIXEL_FORMAT_8888, 0&#41;;

		// make the previous page as the background page for rendering
		currentPage = 1-currentPage;
		pVRAM = pBufferPointer&#91;currentPage&#93;;

		Render&#40;&#41;;		// render all images to buffer
	
	&#125;
	
	FreeImage&#40;bg&#41;;							// free the images
	FreeImage&#40;mario&#41;;
	FreeImage&#40;cursor&#41;;
	
	sceKernelExitGame&#40;&#41;;
	return 0; 
&#125; 
casual otaku
Posts: 3
Joined: Wed Dec 14, 2005 4:53 am

Post by casual otaku »

Thanks for posting the code, but it's not much use to me because you haven't included the parts that initialise variables such as pVRAM, FRAME_BUFFER_SIZE and FRAME_BUFFER_WIDTH? If you provide me with this info then I can try to integrate your code into mine in order to implement double buffering.

Thanks
dr_watson
Posts: 42
Joined: Mon Nov 28, 2005 11:30 am

Post by dr_watson »

I was trying to just give you an idea on how to do double buffering so I only posted a code segment :)

Here is the complete source code:
http://www.khors.com/JGE/game04_src.zip
(You'll need libpng to build it)

If you want to use Gu instead, you can have a look of the source code of my game StarBugz:

http://forums.ps2dev.org/viewtopic.php?t=4286
casual otaku
Posts: 3
Joined: Wed Dec 14, 2005 4:53 am

Post by casual otaku »

Thanks! I doubt I'll need that PNG library as I'm only interested in the double buffering stuff and not the imaging. I'll give it a go later today.

Again, thanks.
jsharrad
Posts: 100
Joined: Thu Oct 20, 2005 3:06 am

Post by jsharrad »

Here is the complete source code:
http://www.khors.com/JGE/game04_src.zip
(You'll need libpng to build it)
Built that fine, but when I tried to run it on my psp, it just turned off:(
Warrick
Posts: 9
Joined: Tue Dec 06, 2005 6:49 am

Post by Warrick »

jsharrad, do you also copy all png resources of game 04 to correct directory?
Post Reply