Speed issues

Recommended Posts

Im developing an isometric tile engine for an RTS game and it
runs terribly slow(Spec: 200MHz, 64MB, 2MB VRAM). I dont
expect it to run very fast with my crappy video-card but when
i run other RTS games like Age of Empires II the speed
is perfectly accebtable.
I have clocked different parts of the program and located the
problem to the Blt-function:
lpddsMapView->Blt(&rMapCoords[x][y],lpddsBasicTileSet[iTileNr],
NULL, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
This function is repeated x*y times and stores
the part of the map that will be seen onscreen. Then it is
blitted to the backbuffert(this reduces the number of blitts
heavily when the user doesnt scroll much).
Is there any other(faster) way to do this? The source codes
ive looked at all use a variant of this method(and BltFast).
Thanks in advance.

Share this post

Link to post

Share on other sites

For comparison, you might want to try BMDXCtls. It''s a 2-D DirectDraw tile engine written in VC++. I know this runs acceptably fast on many computers, so you can see how fast your code runs compared to this. It''s open source and is available as part of The Scrolling Game Development Kit. To download just the BMDXCtls source code, you''ll want to visit the File List.

Of course since it''s open source, you could also change it and see what effect certain changes have, and see how it works. I did use BltFast in this engine.

If you need a program that *uses* the tile engine (and can''t make a test program for it in VB or something, using the included help file), just download the Scrolling Game Development Kit itself. It installs BMDXCtls.dll as part of its install (it will un-install it during the un-install also). Anything that switches to full screen mode uses BMDXCtls. It also appears that the sample "Maze" game is still available out there at http://members.nbci.com/win32realm/codecity/directx/bmdxctls/ if you want a smaller sample program that uses BMDXCtls.

"All you need to do to learn circular logic is learn circular logic"

0

Share this post

Link to post

Share on other sites

Guest Anonymous Poster

Guest Anonymous Poster

You might want to go with a dirty rectangle scheme,which will eliminate redundtant overdraw of unchanged areas. It was nessecary for any type of 2d game back when cards were alot more limited. However it has fallen out of favor, as of late. Basically you somehow much keep a record of changes to the screen. Of course if the screen is scrolling you will have to blt the whole thing, however if you noticed games like AOE the screen isnt scrolling most of the time. It''s usually fixed. So a simple method divide up the 2ndry buffer into an evenly grided rectangle. When you blt to this 2nd buffer mark down the rectangles which have been touched by the blt rect. Do this for all the blts. Once done coallate the dirty rectangles if need be, that is try to elminiate multiple blt overheads of many small areas if you can group them without too much redundancy. Once that''s done blt those rects which only have changed to screen. You should get about 2x speed increase using this system, as most of the screen isn''t changing, also as you increase resolution the benifits become even greater as amount of info you have to pass using a single fullscreen blt increases faster than the blt overhead of the diry rect system, which stays pretty much constant.

Good Luck

-ddn

0

Share this post

Link to post

Share on other sites

Guest Anonymous Poster

Guest Anonymous Poster

As i was reading your post again it seems that you might be redrawing the entire screen irrespective of any changes to the buffer. The dirty rectangle method will still work for you but you''ll have to add an addition to it.

You''ll need to implement a history buffer for each of the rects and run through the blt cycle 2 times. The first is to collect a blt history for each rect (dont draw anything on this cycle). Compare that to the old blt history if they are the same, nothing has change and avoid blting any tiles into that area. For those rects which have change queue up all unique blts and blt them in order (this is where you actually draw stuff to the 2ndary buffer). Then draw the dirty rects. This should get you savings on the tile by tile blts as well as the 2ndary to screen blts.

Share this post

Link to post

Share on other sites

Worst of all this function seems to be at the mercy of the vid driver''s particular fancy ... let me explain a bit more to make myself clearer.

I wrote an iso engine in ddraw using blt, thinking that things were cool since I was getting *ok* fps on my system which is fairly modest (PII-350/Diamond viper 550) assuming the majority of other setups would run my app better. I did a few driver switches and found my app could lose a lot of ground, my frame rate halved sometimes. Then I ran tests on 10 or so other boxes all better than mine. I got frame rates ranging from *1* frame a second up to more than *40* fps, running the same .exe

IMO - If you want smooth scrolling at 600 * 480 * 8 or above *don''t* use blt - in fact I''d even go so far as to say avoid 2d, cards/drivers just don''t want to know about it.

KalvinB : The advice to use bltfast and clip yourself, the same advice you gave me. What exactly are you suggesting ? On the fly creation of custom surfaces ? On the fly data manipulation of existing surfaces ?

Share this post

Link to post

Share on other sites

As long as I dont scroll I now have an acceptable speed.But as soon as I scroll, the entire buffer must be re-blitted.This takes more than 500ms and practically makes it unscrollable.

Anyone know how to effectively do this(scroll)?By the way, I dont use "smooth scrolling". I scroll tile by tile to keep up the speed(in vain obviously :-).

asd_de: You say I should either put everything in the video-memory or the system-memory, why? I dont have enough VRAM to hold more than one of the surfaces, should I explicitly put it in systemmemory? Does that give better performance?

0

Share this post

Link to post

Share on other sites

One way you might want to think about is - use bltfast and cover up the frayed tile edges with a frame. This way you don''t need clipping and can use bltfast. Might be significantly faster (probably will be). This method obviously looks better if you have smaller size tiles. Or if you have larger tiles maybe cover the frayed edges with other parts of the gui.

Yeah it sounds like a pissweak cop-out but done tastefully it can look ok. This is ok for tile by tile scrolling but for smooth scrolling it won''t work.

El Duderino

0

Share this post

Link to post

Share on other sites

I know some cards doesnt support BltFast but in those cases I thought directdraw emulated it for you... I cant even use the function. I use this line:lpddsMapView->BltFast(400, 500, lpddsBasicTileSet[NR_WATER_1], NULL, DDBLTFAST_WAIT);

Share this post

Link to post

Share on other sites

1. Before you actually blit check to see that the destination puts the tile entirely on the screen. If it doesn''t do the following.

2. See how far off the screen it is. If the destination puts the tile completely off the screen then just skip it and move to the next otherwise move to the next step.

3. See how far off the screen it is the adjust where you grab it from the offscreen surface. If it''s two pixels too far off the right side, shorten the ImageRect.right two pixels. And so forth. The left and top are a little more complicated since you then have to adjust where it''s placed as well.

Benhttp://therabbithole.redback.inficad.com

0

Share this post

Link to post

Share on other sites

However, AFAIK only the blt function allows you the freedom to manipulate the dest and source RECTs. Bltfast does not, you just pass a single x,y co-ord and that''s that, surface gets smacked on surface no-frills.

Share this post

Link to post

Share on other sites

get TANSTAAFLs book on isometric programming. I have an example source code and program on the cd, called "TBS for Contest" (I thought TANSTAAFL would change the name, hehe). I use bltfast and do my own clipping. Its much faster and better then using blt. Here is how it works:

The RECT is used for clipping the image. This example here will blit that whole bitmap. But you would use the RECT to select the portions of the bitmap that you want to see, for example, if half of the tile was off of the screen, you would use the RECT to select just the pixels of the bitmap that will appear on the screen.

In the demo on the cd, I basically make a civ2 engine, but using hexagons.