|
[A5] Double buffering |
ehguacho
Member #13,054
July 2011
|
hi everyone! i'm having some issues while double buffering in A5. this my code: 1void CEmulator::DrawFrame()
2{
3 ALLEGRO_BITMAP *DoubleBuffer = al_create_bitmap(256, 240);
4 al_set_target_bitmap(DoubleBuffer);
5 for(int x = 0; x < 256; x++)
6 {
7 for(int y = 0; y < 240; y++)
8 {
9 ALLEGRO_COLOR Color = al_map_rgb((ScreenBuffer[x][y] & 0xFF0000) >> 16, (ScreenBuffer[x][y] & 0x00FF00) >> 8, ScreenBuffer[x][y] & 0x0000FF);
10 al_put_pixel(x, y, Color);
11 }
12 }
13 al_set_target_bitmap(al_get_backbuffer(Screen));
14 al_draw_bitmap(DoubleBuffer, 0, 0, 0);
15 al_flip_display();
16}
...where ScreenBuffer is an array where i'm storing color information encoded in long format (e.g.: 0xFFFFFF is white). on the other hand, i can do that like this: 1void CEmulator::DrawFrame()
2{
3 al_set_target_bitmap(al_get_backbuffer(Screen));
4 for(int x = 0; x < 256; x++)
5 {
6 for(int y = 0; y < 240; y++)
7 {
8 ALLEGRO_COLOR Color = al_map_rgb((ScreenBuffer[x][y] & 0xFF0000) >> 16, (ScreenBuffer[x][y] & 0x00FF00) >> 8, ScreenBuffer[x][y] & 0x0000FF);
9 al_put_pixel(x, y, Color);
10 }
11 }
12 al_flip_display();
13}
this last piece of code works fine, but the problem is that is very slow, since the display isn't double buffered. any hints on how can i solve this problem? thank you all in advance! |
Matthew Leverton
Supreme Loser
January 1999
|
It already is double buffered. You just need to lock the bitmap with al_lock_bitmap() to gain speed. |
ehguacho
Member #13,054
July 2011
|
thanks for your fast reply! i've gained some speed, but still is pretty slow... 1void CEmulator::DrawFrame()
2{
3 ALLEGRO_BITMAP *DoubleBuffer = al_create_bitmap(256, 240);
4 al_set_target_bitmap(DoubleBuffer);
5 al_lock_bitmap(DoubleBuffer, al_get_bitmap_format(al_get_backbuffer(Screen)), ALLEGRO_LOCK_WRITEONLY);
6 for(int x = 0; x < 256; x++)
7 {
8 for(int y = 0; y < 240; y++)
9 {
10 ALLEGRO_COLOR Color = al_map_rgb((ScreenBuffer[x][y] & 0xFF0000) >> 16, (ScreenBuffer[x][y] & 0x00FF00) >> 8, ScreenBuffer[x][y] & 0x0000FF);
11 al_put_pixel(x, y, Color);
12 }
13 }
14 al_unlock_bitmap(DoubleBuffer);
15 al_set_target_bitmap(al_get_backbuffer(Screen));
16 al_draw_scaled_bitmap(DoubleBuffer, 0, 0, 256, 240, 0, 0, 256 * PixelSize, 240 * PixelSize, 0);
17 al_flip_display();
18}
am i doing something wrong? |
Matthew Leverton
Supreme Loser
January 1999
|
You don't need that DoubleBuffer. You already have a double buffer by virtue of creating a display. Furthermore, you definitely do not want to be creating a bitmap on every frame. |
Edgar Reynaldo
Major Reynaldo
May 2007
|
Also, unless your ScreenBuffer array changes, you should draw it into a bitmap once, and then draw that bitmap instead of using al_put_pixel. And even if it does change, you may still want to have the results buffered in a bitmap, and only draw to it the parts that have changed. My Website! | EAGLE GUI Library Demos | My Deviant Art Gallery | Spiraloid Preview | A4 FontMaker | Skyline! (Missile Defense) Eagle and Allegro 5 binaries | Older Allegro 4 and 5 binaries | Allegro 5 compile guide |
ehguacho
Member #13,054
July 2011
|
tried that already, but it's still VERY slow... 1void CEmulator::DrawFrame()
2{
3 al_set_target_backbuffer(Screen);
4 al_lock_bitmap(al_get_backbuffer(Screen), al_get_bitmap_format(al_get_backbuffer(Screen)), ALLEGRO_LOCK_WRITEONLY);
5 for(int x = 0; x < 256; x++)
6 {
7 for(int y = 0; y < 240; y++)
8 {
9 ALLEGRO_COLOR Color = al_map_rgb((ScreenBuffer[x][y] & 0xFF0000) >> 16, (ScreenBuffer[x][y] & 0x00FF00) >> 8, ScreenBuffer[x][y] & 0x0000FF);
10 al_put_pixel(x, y, Color);
11 }
12 }
13 al_unlock_bitmap(al_get_backbuffer(Screen));
14 al_flip_display();
15}
obviously there's something that i'm missing here... |
ehguacho
Member #13,054
July 2011
|
Edgar Reynaldo said: Also, unless your ScreenBuffer array changes, you should draw it into a bitmap once, and then draw that bitmap instead of using al_put_pixel. And even if it does change, you may still want to have the results buffered in a bitmap, and only draw to it the parts that have changed. i can't do that, since what i'm developing is a NES emulator, so i can't know when the screen objects changes. |
Matthew Leverton
Supreme Loser
January 1999
|
How do you create ScreenBuffer? Is there a reason you cannot use a bitmap directly? (Edit: You probably cannot, depends on what techniques you are using to keep ScreenBuffer updated.) You can also lock bitmaps this way: 1ALLEGRO_BITMAP *bmp = al_get_backbuffer(Screen);
2ALLEGRO_LOCKED_REGION *lock;
3uint8_t *data;
4int row_size;
5
6al_set_target_bitmap(bmp);
7lock = al_lock_bitmap(bmp, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_WRITEONLY);
8data = lock->data;
9row_size = lock->pitch; // or simply row_size = 4 * 256;
10if (row_size < 0) row_size = -row_size;
11
12for (int y = 0; y < 240; ++y, data += lock->pitch)
13{
14 memcpy(data, &ScreenBuffer[y][0], row_size);
15}
16al_unlock_bitmap(bmp);
Untested. You are storing your ScreenBuffer as [x][y], but you should store it [y][x] for fastest access. |
ehguacho
Member #13,054
July 2011
|
despite i'm rendering 256*240 = 61440 pixels, which is a lot, i've never had speed issues with A4, but now i need A5 because i've to render 2 separate windows. ScreenBuffer is just an array of long values: long ScreenBuffer[256][240]; ...wich i'm filling with some of these values: 1static const long PALETA[64] =
2{
3 0x757575, 0x271B8F, 0x0000AB, 0x47009F, 0x8F0077, 0xAB0013, 0xA70000, 0x7F0B00,
4 0x432F00, 0x004700, 0x005100, 0x003F17, 0x1B3F5F, 0x000000, 0x000000, 0x000000,
5 0xBCBCBC, 0x0073EF, 0x233BEF, 0x8300F3, 0xBF00BF, 0xE7005B, 0xDB2B00, 0xCB4F0F,
6 0x8B7300, 0x009700, 0x00AB00, 0x00933B, 0x00838B, 0x000000, 0x000000, 0x000000,
7 0xFFFFFF, 0x3FBFFF, 0x5F97FF, 0xA78BFD, 0xF77BFF, 0xFF77B7, 0xFF7763, 0xFF9B3B,
8 0xF3BF3F, 0x83D313, 0x4FDF4B, 0x58F898, 0x00EBDB, 0x000000, 0x000000, 0x000000,
9 0xFFFFFF, 0xABE7FF, 0xC7D7FF, 0xD7CBFF, 0xFFC7FF, 0xFFC7DB, 0xFFBFB3, 0xFFDBAB,
10 0xFFE7A3, 0xE3FFA3, 0xABF3BF, 0xB3FFCF, 0x9FFFF3, 0x000000, 0x000000, 0x000000
11};
|
Matthew Leverton
Supreme Loser
January 1999
|
ehguacho said: ScreenBuffer is just an array of long values: Right ... switch to be [y][x] (an array of horizontal lines) and try my memcpy code. (And if you don't want to change your code a lot to test that out, simply pretend the display is 240x256 and draw it sideways.) |
ehguacho
Member #13,054
July 2011
|
i swapped Xs and Ys and got more speed. thanks a lot for that! data = lock->data; "invalid conversion from 'void *' to 'uint8_t *'". i've tried to change the line to: data = (void *)lock->data; ..and to: data = (uint8_t *)lock->data; ...but then nothing comes up to the screen. any hints? |
Matthew Leverton
Supreme Loser
January 1999
|
ehguacho said: "invalid conversion from 'void *' to 'uint8_t *'". i've tried to change the line to: With C++ you need to cast it to uint8_t * yourself. Does this make any difference? memcpy(data, ScreenBuffer + y, row_size); Hmm, maybe it's picking up 0 for the alpha. Try using these as your colors: 0xFF757575... note the 0xff for alpha. Or maybe use this format: ALLEGRO_PIXEL_FORMAT_XRGB_8888 Not sure, but maybe the X means no alpha. |
ehguacho
Member #13,054
July 2011
|
added the "0xFF" prefix to all of the color codes and nothing. |
Matthew Leverton
Supreme Loser
January 1999
|
I still think you can do this: ALLEGRO_BITMAP *ScreenBuffer = al_create_bitmap(256, 240); And draw to it directly. Then use al_draw_bitmap() once per frame. You can try out some of the techniques on this thread as opposed to using al_put_pixel() on it. |
ehguacho
Member #13,054
July 2011
|
ok, now i have speed ^^ but now i have another problem (no joke! please don't hit me :S). the image i'm getting is just 256*250 pixels. how can i enlarge it to a 512*480 pixels? i have the same old speed issues while using al_draw_scaled_bitmap(). there's another memcpy() routine out there that allows me to do that? by the way, ALLEGRO_PIXEL_FORMAT_ARGB_8888 gave me the best performance |
Matthew Leverton
Supreme Loser
January 1999
|
With Windows (Direct3D) this might do the trick: d = al_create_display(256, 240); al_resize_display(d, 512, 480); If you don't acknowledge the resize event, the backbuffer stays the original size. I'd be interested to know if that works. Otherwise... what did you end up doing? Did you convert ScreenBuffer to an ALLEGRO_BITMAP? How are you drawing to it? |
ehguacho
Member #13,054
July 2011
|
just build the app as a GUI app. you have to see it! it just flyes thanks for your replies! |
Elias
Member #358
May 2000
|
Matthew Leverton said: If you don't acknowledge the resize event, the backbuffer stays the original size. I'd be interested to know if that works. Oh god. What are you teaching people here -- |
|