GP32 Gp32 Tutorial 02 "doube Buffering"


synkro

0xdeadbeef
Joined
Aug 26, 2003
Messages
823
Location
Germany
Website
Visit site
Code:
/*
 * GP32 Tutorial 02 "Doube Buffering"
 *
 * Intro
 * -----
 * This time we learn something about double buffering, an essential
 * technique. The idea is that instead of drawing directly on the screen
 * you just show an already "rendered" frame while we work on the next. After
 * drawing on the second framebuffer we flip both showing the second one and
 * and drawing on the first. Double buffering prevents the screen from flickering.
 *
 * Let's bring it on!
 * ------------------
 * 0. #define WIDTH  320
 *    This statement allows you to set up macro definitions. The word
 *    immediately after the #define, together with its arguments, is
 *    expanded in the program text to the whole of the rest of the line.
 *    In this case WIDTH will be replaced with 320. Keep on mind that WIDTH
 *    is not a variable.
 *
 * 1. unsigned short *framebuffer2;
 *    We want to use two framebuffers this time so we have to declare two
 *    pointers and point them to framebuffer data elements. unsigned short
 *    some kind of a smaller integer.
 *
 * 2. framebuffer2 = (unsigned short*) (FRAMEBUFFER + (WIDTH*HEIGHT*2));
 *    we point framebuffer1 to the primary FRAMEBUFFER. We also have to
 *    to point framebuffer2 next to the first framebuffer. But how to
 *    calculate the size of a framebuffer? We need this as an offset to
 *    determine where the second framebuffer begins.
 *    The screen resolution is 320x240 pixel. We are using the 16bit mode,
 *    so every pixel has 16bit color depth. The memory is aligned bytewise,
 *    so we need 16bit = 2byte per pixel. That makes 320*240*2 bytes for a
 *    framebuffer.
 *
 * 3. gp_SetView(framebuffer1);
 *    To make a framebuffer visible on screen we use this function, it needs
 *    a pointer to a framebuffer as argument. As long as we a are showing the
 *    first framebuffer we can do with the second what ever we want.
 *
 * 4. gp_SetFont8(30, 110, 20, "This is framebuffer2", 0xF800, framebuffer2);
 *    This line draws red text on framebuffer2 at (30,110), but why is the
 *    text red? We know that every pixel has 16bit color depth
 *    (RRRRRGGGGGBBBBB0 = 16 bit) the first five bits are red the next five
 *    bits are green and the next blue. The last bit is unused.
 *    For red you need 1111 1000 0000 0000 = 0xF800, that's all!
 *
 * 5. for (i=0; i<9000000; i++) i=i;
 *    This for loop does nothing but wasting time, this is a very ugly way to
 *    make the GP32 wait for a moment. We will later learn how to use timers.
 *    The for loop runs as long as the condition (i<9000000) is true. This is
 *    a really ulgy way to do that, the GP32 offers a real time clock for this.
 *
 * Oh boy! We learned a thing this time. Again try to re-type the following
 * code and try to understand it. As you know it does not make any sense
 * if you cheat yourself with copy and paste. This tuto was rather short but
 * double buffering is so essential it needs its own chapter. I guess that
 * you still don't understand what pointers really are. I will explain this
 * painfull topic in one of the next tutos, till then try this:
 * A) Instead of adding the text directly in the SetFont8 function,
 *    try to use a char array (char []) like in chapter one.
 * B) Look up any SDK function used in this and in the last tutorial in the
 *    SDK manual.
 * C) Give framebuffer1 a red and framebuffer2 a blue background.
 *
 * Disclaimer
 * ----------
 * This Tutorial is based on Mr. Mirko's SDK (mirko@mirkoroller.de)
 * download it at: http://home.t-online.de/home/mirkoroller/gp32/
 * THIS TUTORIAL IS NOT WRITTEN BY MR. MIRKO! Parts of this Tutorial
 * are from the SDK examples or manual.
 * If you have any questions on this please try first to get the needed
 * info on www.gp32x.de or #gp32dev (EFNET) before contacting the author.
 *
 *                                SDK by Mr. Mirko mirko@mirkoroller.de
 *                           Tutorial by synkro    synkro@gmx.net
 *                                                 26.04.2004 14:19:21
 */

#include <gp32.h>

#define WIDTH  320  // We don't have to remember this all the time
#define HEIGHT 240  // when we defined it once.

unsigned short *framebuffer1;
unsigned short *framebuffer2;
// We declare two framebuffer pointers

int main(void)
{

  int i;

  framebuffer1 = (unsigned short*)  FRAMEBUFFER;
  // This sets the framebuffer1 pointer to 0x0C7B4000, the
  // start of the memory area for the screen.
  framebuffer2 = (unsigned short*) (FRAMEBUFFER + (WIDTH*HEIGHT*2));
  // A framebuffer has a size of 320*240*2 bytes. This is the
  // offset we add to the primary framebuffer.

  gp_SetScreen(framebuffer1,16);
  // We only have to set the primary framebuffer into 16bit mode.

  for (i=0; i<WIDTH*HEIGHT; i++) // this for loops goes through all pixel
  {                              // on a framebuffer.
    framebuffer1[i] = 0xFFFF;    // Sets the i-th pixel white on framebuffer1
    framebuffer2[i] = 0xFFFF;    // this does the same with framebuffer2
  }

  gp_SetCpuSpeed(66);

 while (1)
 {

   gp_SetView(framebuffer1);
   // Display of framebuffer1
   for (i=0; i<WIDTH*HEIGHT; i++) framebuffer2[i] = 0xFFFF;
   // Clear framebuffer2
   gp_SetFont8(30, 110, 20, "This is framebuffer2", 0xF800, framebuffer2);
   // Drawing text on framebuffer2

   for (i=0; i<9000000; i++) i=i;
   // This is a waiting loop. We need this because the GP32
   // would change the framebuffers too fast. We would see
   // it only flickering.

   gp_SetView(framebuffer2);
   // Display of framebuffer2
   for (i=0; i<WIDTH*HEIGHT; i++) framebuffer1[i] = 0xFFFF;
   // Clear framebuffer1
   gp_SetFont8(30, 100, 20, "This is framebuffer1", 0xF800, framebuffer1);
   // Drawing text on framebuffer1

   for (i=0; i<9000000; i++) i=i;

 }

}
 
Last edited by a moderator:
Could you please explain why the offset contains WIDTH*HEIGHT*2 but the while loops only contain WIDTH*HEIGHT?
 
1. you calculate the offset to the next framebuffer. the memory is ordered bytewise so you have to calculate it bytewsie. Every pixel has a color space of 16bit = 2byte,so the offset is two times 320*240.

2. during the for loops we use i as index for array (framebuffer) of unsigned shorts. An unsigned short has a length of 16bit so a framebuffer has 320*240 of it (every pixel is stored in 16bit, so we need 320*240*2 bytes space for it but there are only 320*240 elemts)
 
Since the first framebuffer pointer is already defined as a unsigned short, when you offset the pointer, i believe it moves at the size of 1 short per offset. That is to say that I don't believe it is moving 1 byte at a time.

Try it without the *2 and see if I'm right. It could work diferently when you are initialising the variable, but i doubt it.
 
How come in a computer you generally do X+640(or whatever memory line is)*y. Does this mean the memory line(or buffer or refresh rate or whatever you call it) is only 2 in the GP32.
 
640 is the width of the frambuffer you just took that code out from. X+640*Y would give you the index to the correct pixel for X & Y. For a 320*240 display, you would want to change that to say X+320*Y though even that is incorrect for the GP32 as the screen is actually mounted sideways with the bottom left being 0,0. What you would need is X*240+239-Y. (i think :))
 
Daz_Genetic posted on May 4 2004 at 07:15 PM said:
Since the first framebuffer pointer is already defined as a unsigned short, when you offset the pointer, i believe it moves at the size of 1 short per offset. That is to say that I don't believe it is moving 1 byte at a time.

Try it without the *2 and see if I'm right. It could work diferently when you are initialising the variable, but i doubt it.
we add he offset to FRAMEBUFFER which is just at constant memory adress, to calculate the beginning of the next framebuffer we have to count bytewise. without *2 it doesn't work.
 
Last edited by a moderator:
Daz_Genetic posted on May 4 2004 at 08:13 PM said:
Ahh yes I see.. so you could do it that way, or you could do it
Code:
framebuffer2 = (unsigned short*) (framebuffer1 + (WIDTH*HEIGHT);
fine, this is a more elegant way, I guess I will add it to the next tutos, because so it makes more sense
 
Last edited by a moderator:
synkro posted on May 5 2004 at 10:08 AM said:
Daz_Genetic posted on May 4 2004 at 08:13 PM said:
Ahh yes I see.. so you could do it that way, or you could do it
Code:
framebuffer2 = (unsigned short*) (framebuffer1 + (WIDTH*HEIGHT);
fine, this is a more elegant way, I guess I will add it to the next tutos, because so it makes more sense
Yah the new way makes much more sense to me now, because the old way just contained the default FRAMEBUFFER and not the framebuffer1 that you had put before.
 
Last edited by a moderator:
Back
Top