Double Buffering

Marc Lepage wrote:

[cut]

In short, is there a best way to draw this other than the naive method:
draw everything into a back buffer without update, then flip to
onscreen? That’s how I did it in GTK+. I didn’t have much of a problem
attaining 30fps for few visible units, 20fps for many. Yet, as you can
see from the screenshot, that particular window takes 25fps to draw
without computing game logic or drawing much game action.

I’ve been thinking about this, and I have a question for Sam: when data
is sent through he TCP socket connection to the X server, does the
calling program block for a significant amount of time? Can Marc improve
his performance by using a thread to make the updates?

The entire code that draws that window is in one file,
http://www.antimeta.com/projects/minion/main.cpp. It relies on SDL, SGE,
and SDL Console. [Comments appreciated. The sooner I can get these
issues out of the way, the sooner I can start getting the actual game
logic back in.]

Could it be my use of SGE and SDL Console that is so slow? My use of
BMPs (I haven’t converted images or anything)?

Marc, can you compile your program with profiling support and post some
numbers? It would be interesting to see how much time the various
components consume.

Thanks for all your help on this list! PS, any other RTS games done in
SDL?

MJP

In short, is there a best way to draw this other than the naive method:
draw everything into a back buffer without update, then flip to
onscreen? That’s how I did it in GTK+. I didn’t have much of a problem
attaining 30fps for few visible units, 20fps for many. Yet, as you can
see from the screenshot, that particular window takes 25fps to draw
without computing game logic or drawing much game action.

The entire code that draws that window is in one file,
http://www.antimeta.com/projects/minion/main.cpp. It relies on SDL, SGE,
and SDL Console. [Comments appreciated. The sooner I can get these
issues out of the way, the sooner I can start getting the actual game
logic back in.]

Hi Marc,

It is possible that using some of the SGE calls (I haven’t looked at SDL
Console) is slowing down your code. For example, in your drawUnit function,
you call sge_Circle - I believe that doing a straight blit from a converted
surface would be faster. You might try drawing your circles onto an SDL
surface with transparency and then blitting those surfaces to the screen.
sge_Circle draws a circle using the sqrt function - quick, but still
more expensive than blitting. I don’t know how much your fps suffers from
this, but for 7 circles and 2 filled circles, it’s gotta be slower than
blitting a bitmap.

You can draw everything to a back buffer, but you will prolly get better
fps if you only update those rectangles that need updating. “If it moves,
blit it; if not, skip it.”

Avoid the painter’s algorithm when blitting back to the screen. For
example, if you have something like:±-------------------+
| |
| Surface A |
| |
| ±--------±----------+
| | | |
| |eliminate| |
| | this | |
| | area | |
| | | |
| | | |
| | | |
| | | |
| | | |
±---------±--------+ |
| |
| |
| Surface B |
| |
| |
±--------------------+

You can avoid drawing the overlap portion by dividing the areas to blit
into 3 rectangles:

±-------------------+
| |
| Surface A1 |
| |
|----------±--------±----------+
| | |
| | |
| Surface | |
| A2 | |
| | Surface B |
| | |
| | |
| | |
| | |
±---------+ |
| |
| |
| |
| |
| |
±--------------------+

This way, you avoid blitting overlapping areas - which can become
real expensive if you have many overlapping pieces.

Keep in mind that blitting to the screen is one of the slower operations
you can perform, so manipulate as much as you can in an off screen buffer
and then blit as little as possible to the screen.

Scrolling is another issue altogether…

Hope this helps. Correct me on anything if I’m wrong…

Robin Sam wrote:

Hi Marc,

It is possible that using some of the SGE calls (I haven’t looked at SDL
Console) is slowing down your code. For example, in your drawUnit function,
you call sge_Circle - I believe that doing a straight blit from a converted
surface would be faster. You might try drawing your circles onto an SDL
surface with transparency and then blitting those surfaces to the screen.
sge_Circle draws a circle using the sqrt function - quick, but still
more expensive than blitting. I don’t know how much your fps suffers from
this, but for 7 circles and 2 filled circles, it’s gotta be slower than
blitting a bitmap.

Unh! sqrt? No Bressenham? I suppose I’ll have to take a bit of time and
code my own. I was hoping to avoid all this, I just want fast
rasterization. It may be of different radius, although I suppose if I
limited it to some finite dozen, I could save the surfaces and blit
them.

Well, my tiles don’t overlap, so that’s okay. It’s units that overlap
terrain, and potentially units that overlap other units (although I
think I’ll implement a kinematic intersection constraint so they never
do so).

You can draw everything to a back buffer, but you will prolly get better
fps if you only update those rectangles that need updating. “If it moves,
blit it; if not, skip it.”

Avoid the painter’s algorithm when blitting back to the screen. For
example, if you have something like:

±-------------------+
| |
| Surface A |
| |
| ±--------±----------+
| | | |
| |eliminate| |
| | this | |
| | area | |
| | | |
| | | |
| | | |
| | | |
| | | |
±---------±--------+ |
| |
| |
| Surface B |
| |
| |
±--------------------+

You can avoid drawing the overlap portion by dividing the areas to blit
into 3 rectangles:

±-------------------+
| |
| Surface A1 |
| |
|----------±--------±----------+
| | |
| | |
| Surface | |
| A2 | |
| | Surface B |
| | |
| | |
| | |
| | |
±---------+ |
| |
| |
| |
| |
| |
±--------------------+

This way, you avoid blitting overlapping areas - which can become
real expensive if you have many overlapping pieces.

That’s similar to the span lists I was asking about. Basically, each
scan line update is stored as a list of updates to perform, like
run-length, and that is easily manipulated. Finally it is drawn once
when everything is calculated. That eliminates overdraw. Of course, in
the absence of overdraw, painter’s algorithm is perfect. With only a
little overdraw, it’s still pretty good.

Keep in mind that blitting to the screen is one of the slower operations
you can perform, so manipulate as much as you can in an off screen buffer
and then blit as little as possible to the screen.

I think for now, I’ll blit each frame in entirety. That’s simple, and in
the worst case (especially scrolling) required. Eventually I may look to
optimize that.–
Marc Lepage
Software Developer
Molecular Mining Corporation
http://www.molecularmining.com/

MJP wrote:

Marc, can you compile your program with profiling support and post some
numbers? It would be interesting to see how much time the various
components consume.

http://www.antimeta.com/projects/minion/gprof.txt

Hm, the killers are in SGE:

Flat profile:

Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
69.76 1.43 1.43 11393502 0.00 0.00
_PutPixel(SDL_Surface *, int, int, unsigned int)
14.15 1.72 0.29 10336 0.03 0.08
sge_VLine(SDL_Surface *, int, int, int, unsigned int)
8.78 1.90 0.18 10336 0.02 0.07
sge_HLine(SDL_Surface *, int, int, int, unsigned int)–
Marc Lepage
Software Developer
Molecular Mining Corporation
http://www.molecularmining.com/

Marc Lepage wrote:

Unh! sqrt? No Bressenham? I suppose I’ll have to take a bit of time and
code my own.

From the Pascal implementation in Hill’s Computer Graphics text, here’s
Michener’s Circle algorithm. It’s based on Bresenham’s algorithm, but
the first difference of the error is now quadratic (instead of linear).
It’s a very efficient iterative algorithm… note that the most
complicated thing happening is multiplication.

void
MichenerCircle(SDL_Surface* pSurface, int xc, int yc, int nRadius,
Uint32 color)
{
// Point
int x = 0;
int y = nRadius;

// Error term
int d = 3 - 2 * nRadius;

while (x <= y)
{
    // What immortal hand or eye
    // Could frame thy fearful symmetry?
    DrawPixel(pSurface, xc + x, yc + y, color);
    DrawPixel(pSurface, xc - x, yc + y, color);
    DrawPixel(pSurface, xc + x, yc - y, color);
    DrawPixel(pSurface, xc - x, yc - y, color);
    DrawPixel(pSurface, xc + y, yc + x, color);
    DrawPixel(pSurface, xc - y, yc + x, color);
    DrawPixel(pSurface, xc + y, yc - x, color);
    DrawPixel(pSurface, xc - y, yc - x, color);

    // Error update term
    if (d < 0)
    {
        d += 4 * x + 6;
    }
    else
    {
        d += 4 * (x - y) + 10;
        --y;
    }

    ++x;
}

}–
Marc Lepage
http://www.antimeta.com/
Minion open source game, RTS game programming, etc.

Hey all!

I’m having problems here with using double buffering
on a HWSURFACE in fullscreen mode on Win98SE. It just
doesn’t work, meaning the screen just stays black and
I see no output. The programs don’t crash though. When
I change the framebuffer to a SWSURFACE or switch to
window mode, everything’s just fine. I guess this is a
bug in SDL, isn’t it??
Oh btw, I’m using a GeForce 2 MX400.__________________________________________________
Do You Yahoo!?
HotJobs - Search Thousands of New Jobs
http://www.hotjobs.com

Are you flipping your buffers? You must do that when using double buffering.

int main()
{
//init SDL
screen = SDL_SetVideoMode(…,SDL_DOUBLEBUF | SDL_HWSURFACE);

while(true)
{
	SDL_BlitSurface(screen,.....);
	...
	SDL_Flip(screen);
}

}

you need to call SDL_Flip to bring the back buffer forward to see what you
just drew.

MattOn Thursday 15 August 2002 04:57 am, Erwin Schwarz wrote:

Hey all!

I’m having problems here with using double buffering
on a HWSURFACE in fullscreen mode on Win98SE. It just
doesn’t work, meaning the screen just stays black and
I see no output. The programs don’t crash though. When
I change the framebuffer to a SWSURFACE or switch to
window mode, everything’s just fine. I guess this is a
bug in SDL, isn’t it??
Oh btw, I’m using a GeForce 2 MX400.

— Matt Greer wrote:

Are you flipping your buffers? You must do that when
using double buffering.

int main()
{
//init SDL
screen = SDL_SetVideoMode(…,SDL_DOUBLEBUF |
SDL_HWSURFACE);

while(true)
{
SDL_BlitSurface(screen,…);

SDL_Flip(screen);
}
}

you need to call SDL_Flip to bring the back buffer
forward to see what you
just drew.

Matt

Yes, of course I’m flipping the buffers. It doesn’t
work anyway… :(__________________________________________________
Do You Yahoo!?
HotJobs - Search Thousands of New Jobs
http://www.hotjobs.com

— Erwin Schwarz wrote:

Hey all!

I’m having problems here with using double buffering
on a HWSURFACE in fullscreen mode on Win98SE. It
just
doesn’t work, meaning the screen just stays black
and
I see no output. The programs don’t crash though.
When
I change the framebuffer to a SWSURFACE or switch to
window mode, everything’s just fine. I guess this is
a
bug in SDL, isn’t it??
Oh btw, I’m using a GeForce 2 MX400.

Come on, doesn’t anybody have an idea or similar problems??__________________________________________________
Do You Yahoo!?
HotJobs - Search Thousands of New Jobs
http://www.hotjobs.com

I’m having problems here with using double buffering
on a HWSURFACE in fullscreen mode on Win98SE. It
just
doesn’t work, meaning the screen just stays black
and
I see no output. The programs don’t crash though.
When
I change the framebuffer to a SWSURFACE or switch to
window mode, everything’s just fine. I guess this is
a
bug in SDL, isn’t it??
Oh btw, I’m using a GeForce 2 MX400.
Come on, doesn’t anybody have an idea or similar problems??

What video mode are you running in? I had a similar problem like this with
my emulator, and it turned out I didn’t set up the hardware palette to be
the same as my backbuffer palette, and everything wound up being black.
;-(

Also, are you creating your backbuffer on the card itself? If you’re doing
2D graphics, this will always be slower than creating an in memory
backbuffer and blitting the changes on a per frame basis. PCI/AGP
Transactions are expensive timewise compared to main system memory. That
goes for all platforms.

–>Neil-------------------------------------------------------------------------------
Neil Bradley What are burger lovers saying
Synthcom Systems, Inc. about the new BK Back Porch Griller?
ICQ #29402898 “It tastes like it came off the back porch.” - Me

Have you tried compiling any of the NeHe SDL examples? I seem to remember
that they all use hardware double buffering… it they work, you can examine
them for how they differ from your code.> ----- Original Message -----

From: bombenhagel666@yahoo.com (Erwin Schwarz)
To:
Sent: Thursday, August 15, 2002 1:57 PM
Subject: Re: [SDL] Double Buffering

— Erwin Schwarz wrote:

Hey all!

I’m having problems here with using double buffering
on a HWSURFACE in fullscreen mode on Win98SE. It
just
doesn’t work, meaning the screen just stays black
and
I see no output. The programs don’t crash though.
When
I change the framebuffer to a SWSURFACE or switch to
window mode, everything’s just fine. I guess this is
a
bug in SDL, isn’t it??
Oh btw, I’m using a GeForce 2 MX400.

Come on, doesn’t anybody have an idea or similar problems??


Do You Yahoo!?
HotJobs - Search Thousands of New Jobs
http://www.hotjobs.com


SDL mailing list
SDL at libsdl.org
http://www.libsdl.org/mailman/listinfo/sdl