Archived

This topic is now archived and is closed to further replies.

d_prodigy

Speed issues

Recommended Posts

d_prodigy    122
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
asd_de    122
Hello,



1. Try not to draw anything that is not on screen, even running a plain loop with nothing inside 10k times every frame will slow down your program considerably

2. As Blt() does resizing automatically, make sure that source and target rectangles are exactly the same size, because resizing the picture will cause a big slowdown.

3. Try to put all bitmaps in video or all bitmaps in system memory



asd_de

Share this post


Link to post
Share on other sites
BlueMonk    142
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"

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

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.

Good Luck

-ddn

Share this post


Link to post
Share on other sites
KalvinB    102
Don''t use blt. Use bltfast and do your own clipping.

That should speed it up considerably.

Ben
http://therabbithole.redback.inficad.com

Share this post


Link to post
Share on other sites
El Duderino    122
Yep, blt is the big bottleneck.

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 ?

El Duderino

Share this post


Link to post
Share on other sites
d_prodigy    122
Thanks for all the help.

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?

Share this post


Link to post
Share on other sites
El Duderino    122
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

Share this post


Link to post
Share on other sites
d_prodigy    122
El duderino: Good suggestion. Im trying it out rightaway.

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);

and it fails...
Why??

Share this post


Link to post
Share on other sites
zennehoy    122
It''s been a while since I used ddraw, but I believe you have your paramaters set up incorrectly. Look up the docs on bltfast again and make sure you are passing args in the correct order,
Zen

Share this post


Link to post
Share on other sites
El Duderino    122
Those args seem in the right order.

What dimentions are the lpddsMapView and lpddsBasicTileSet[NR_WATER_1] surfaces ?

If putting the water there at 400, 500 means that *any* pixels are off the MapView surface, nothing will get blitted.

El Duderino

Share this post


Link to post
Share on other sites
KalvinB    102
On the fly clipping is basically this:

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.

Ben
http://therabbithole.redback.inficad.com

Share this post


Link to post
Share on other sites
El Duderino    122
If what you are saying is true KalvinB, it is *very* good news.

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.

I''d be pleased to hear different.

El Duderino

Share this post


Link to post
Share on other sites
Kylotan    9855
I seem to recall that BltFast takes width and height parameters, which are pretty much the same thing as passing in a rectangle anyway.

Share this post


Link to post
Share on other sites
Possibility    122
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:

        
RECT rect;
rect.left = 0;
rect.right = IMAGE_WIDTH;
rect.top = 0;
rect.bottom = IMAGE_HEIGHT;


lpDDSBack->BltFast(x_pos_on_screen, y_pos_on_screen, UnexploredTile_surf, &rect, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY);


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.

Possibility

Edited by - Possibility on July 9, 2001 4:19:18 AM

Share this post


Link to post
Share on other sites