View Full Version : optimising rendering using DirectX7
cliffski
05-17-2006, 04:53 PM
Im using an engine based on DX7 for my '2D using 3D acceleration' game. I want to optimise the rendering so that I'm not going to tax older cards (I have a geforce6800 but want it to run on much older cards).
The best optimising tool I can find is the nvdia perfhud stuff, but the code it requires assumes directx9, which im not using at all. Moving to DX9 seems like mega hassle right now.
Does anyone have any good ideas or tips for speeding up DX7 rendering? I'd love some kind of data on how much Im taxing the fill rate and the poly count. I'd also REALLY like to know when the card stalls, as I do a lot of getDC() to use GDI for text rendering, and I'd love to know when (and how badly) this stalls everything.
Im interested to know the approaches used by people using a 3D engine on casual games so it works fast and reliably on older hardware. Especially using DX7.
thanks.
ggambett
05-17-2006, 05:11 PM
Are you sure you have a problem to begin with? I haven't done any interesting optimizations in our 3D renderers, and Pirate Poppers didn't have any technical problem with requirements. I use D3D7 and I saw the game running in laptops with onboard videocards with 8 MB of RAM.
About the text issue, can you render to a bitmap and convert it to a texture instead of using GDI every frame? I render TrueType fonts with SDL_TTF which is slow but as long as you don't render every frame and reupload the texture every frame, you should be OK.
gmcbay
05-17-2006, 07:05 PM
I don't really have any good suggestions for an automated perf tuner, but I know from experience that calling GetDC even once per frame really can be a framerate killer on some cards.
I second ggambett's suggestion to cache the font to bitmap textures. You can do this at runtime so you have full font flexibility just as you have now, just draw the characters via gdi once (per font/fontsize) and hold onto the results in a resuable D3D texture. As long as you keep the alpha information intact, this can look just as good as if you're rendering them using gdi.
Surprisingly, most games are actually CPU bound. If you are doing a 2D game, chances are even lower that you'll ever be GPU bound, even going back as far as GeForce 2.
To keep CPU overhead down, try to avoid touching the runtime as much as possible. Keep the draw calls under 1000 or so, batch according to render/texture/material state, and follow ggambett's advice about compositing your textures. That should be enough, barring anything silly.
Integrated graphics however are a different story. It's really easy to become framebuffer bandwidth limited on them.
PeterM
05-18-2006, 12:03 AM
If Direct3D is using hardware rendering, and you're batching half-decently, then you're almost guaranteed to be CPU bound.
If you lock anything in D3D you could be stalling your rendering, so ideally you should lock as infrequently as possible, preferably never on a per-frame basis.
Direct3D 7 also has a bug where switching vertex buffer is unusually expensive, so you may want to sort your rendering by vertex buffer first, then by 'shader' then by texture.
Probably the best thing to do if you can't profile on an older card is to find some of the older NVIDIA presentations when D3D7 was the standard. Have a look here, and read the docs from the bottom up:
http://developer.nvidia.com/object/perf_docs_by_date.html
Hope this helps,
Pete
cliffski
05-18-2006, 01:41 AM
I used to do my own font stuff with bitmaps, but the results just arent as elegant as GDI. Are you suggesting just rendering out each character and then piecing words together? or rendering out whole blocks of text , cacheing them, and resuing them each frame?
I find that GDI seems to do a lot of funky smoothing and kerning and so on that makes its text look way better than I could get doing it by blitting.
Democracy uses GDI, and Starship Tycoon uses bitmaps, and I think the Democracy text looks much nicer.
I'm going to poke around a bit mroe and see if I can reduce my GDI locks.
gmcbay
05-18-2006, 05:34 AM
If your text is very static you should be able to get away with just caching full blocks of text, but in my case I drew out all of the printable characters for the font to one texture and then mapped sections of that texture to simple quads (same as the standad 2D/3D sprite drawing trick) to draw individual letters. You could do it more simply by having one sprite/texture per character, but you'd of course waste a lot more vram that way (maybe it wouldn't be a big deal depending upon the situation).
The smoothing should remain intact as long as you properly cache the alpha information that is written to the destination DC's bitmap when you do the drawstring and encode that in the texture (and use a texture format that supports alpha). When I did this I actually used Gdiplus and capturing the alpha along with the rest of the drawn bits (drawn into a 32bit ARGB offscreen bitmap) was very easy. I assume it is possible to do the same with plain old GDI, but probably far more cumbersome (everything is). Getting the kerning to look good is a bit of extra work but not as bad as it seems, I used MeasureString (again, Gdiplus) to measure the width of each character at the font size being used and kept that in an array and used those values when drawing out the characters, so 'i' wouldn't display at the same width as 'A', for example.
[...]Getting the kerning to look good is a bit of extra work but not as bad as it seems, I used MeasureString (again, Gdiplus) to measure the width of each character at the font size being used and kept that in an array and used those values when drawing out the characters, so 'i' wouldn't display at the same width as 'A', for example.
Uhm... thats just proportional font stuff. Kerning is unfortunately more difficult than that.
http://en.wikipedia.org/wiki/Kerning
(So far I havent bothered with that. Its not worth the trouble if there are only a few lines of text.)
TheMysteriousStranger
05-18-2006, 09:22 AM
What you need is mudgefont. Someone on here made it I think. Might have been Larry Hastings. It's a great program that lets you output smoothed tga's with alpha information at various sizes, with various borders/styles, and also exports an xml file with all the widths and offsets you need to make a decent kerning system. Sorry I don't have a link handy. I downloaded it years ago, and I think that was a direct link from a post on the old dexterity forums. Google probably knows where. It took me less than 2 hours to make a fully-featured font system based off of mudge fonts outputs.
digriz
05-18-2006, 09:54 AM
I'm going to poke around a bit mroe and see if I can reduce my GDI locks.
It's worth writing something that you can submit your text & it's positioning to, and then rendering all of the text in one go in your render loop at a later time. That way you should only have one GDI lock per render update.
Personally, i wouldn't use GDI. I tend to go with the texture/vertex buffer method.
cliffski
05-18-2006, 11:06 AM
I cant quite do that because I have draggable overlapping windows ;(
It turns out that slowdowns some testers saw were game loop Sleep() related and not frame rate anyway :D
But I still intend to rearrange stuff to cut down on my GDI locks. I didnt have any compatibility issues with Democracy, but I'm hoping to lower my system reqs.
Applewood
05-18-2006, 03:48 PM
GDI is shit in so many different ways. You should see what's going on inside the innermost loop! The GetDC call may or may not be hurting you based on what else you're doing, but it really is a bad thing to be doing generally and as your target card gets older, the pool of bad things you shouldn't do gets ever deeper.
If you really must use GDI for its few nice advantages/features, you should consider rendering your text into a texture and using that. I don't mean on-the-fly as that would be bad too - just use GDI to make a tileset texture at loadtime in much the same way you would if you'd hand-authored a bitmap font in the first place.
My previous engine did this and it worked a treat. (Well, until I ported it to PS2, which is why I try to rely as little on O/S calls as possible, but that's another topic.)
EDIT: I of course meant rendering a character set, not "text"
cliffski
05-18-2006, 04:02 PM
yes Ive done this before, for older games, and now I've come back to GDI because of the quality. I know it *should* be a bad thing, but Democracy had very little end-user problems. In an ideal world I would have a bitmap font system that looked as nice. I think I notice the nice stuff GDI does more because my games are strategy ones with a LOT of text, often in many different sizes. I think if you only have a few lines of text per screen, rendering to a texture and then doing your own compositing from there is certainly the way to go. Thats obviously how big 3D games do it (The movies did this).
Right now I'm on the fence about redoing it using that approach, because of the work that's involved in getting it right.
As someone pointed out, getting character widths automatically is one thing, but sorting it so that (for example) a VA goes together taking into account the relative position of the 2 characters is another matter. I'm pretty sure that GDI does this.
Don't you wish there was an option in windows to say "just render like a card with half the memory and draw speed" so you could check this stuff easily?
Im concluding that even if I had some mega debugging stuff that told me my GDI calls werent a bottleneck, its only going to be true for MY card anyway ;(
Fabio
05-19-2006, 12:21 AM
Don't you wish there was an option in windows to say "just render like a card with half the memory and draw speed" so you could check this stuff easily? For a start they could add "at next reboot simulate x physical memory" (where x is of course <= your max physical memory), so that I could test my proggies on PCs with less than my gig without having to remove the sticks or even having to buy small ones (since I can't cut in half a 512MB one anyway).
It's astonishing how simple options things like this never appeared in twentyfive years of PCs.
Now you'll see Bill Gates feature it and promote as something smart and cool (well, still better than promoting it as an absolute innovation like he did with Windows95's preemptive multitasking after that the Amiga had a MUCH better one already 13 years before, ouch).
Don't you wish there was an option in windows to say "just render like a card with half the memory and draw speed" so you could check this stuff easily?
Im concluding that even if I had some mega debugging stuff that told me my GDI calls werent a bottleneck, its only going to be true for MY card anyway ;(
For draw speed, you can always lower the clocks...
Applewood
05-19-2006, 01:25 AM
Just find yourself a TNT2 PCI card and stick that in (either for your second monitor or on a switch if you only have one). They should be about 5 bucks by now if you can even find someone to sell you one.
It's dead easy to fire that up as your games main target.
Savant
05-19-2006, 06:21 AM
Well, and then there are people developing on laptops...
Applewood
05-19-2006, 06:29 AM
Yeah, I couldn't envisage trying to develop games without the right kit.
If you're developing for a wide (especially low-end) pc audience you should really have an entire box full of older video cards lying around, and something to test them in.
MarkSide
05-19-2006, 07:53 AM
You might also want to look into using Thom Wetzel's "Bitmap Font Builder (http://www.lmnopc.com/bitmapfontbuilder/)" tool, possibly using DrunkenHyena's dhFastFont (http://www.drunkenhyena.com/pages/projects/dhfastfont.cgi) code as an example of how to do this. I found it quite simple to setup and integrate with my code, though dhFastFont appears to be DirectX 8+ only.
If nothing else, I think it's a good reference for creating your own sprite-based text library.
PeterM
05-19-2006, 11:54 AM
Things like localization and/or unicode characters make packing a whole font onto a texture difficult, making a caching system necessary.
I would probably go for some kind of LRU phrase-id-to-texture mapping, but it depends on your requirements/workload involved/benefits gained.
Kai Backman
05-26-2006, 02:21 PM
After trying a few solutions (like prerendered bitmap fonts) I ended up using FreeType to render the text into a piece of texture and re-render it when the text changes. To make this efficient I pick the label sizes to match frequency of change. Frequently changing text will take effort anyway, you either need to hack VB's or upload textures. This solution works OK to the extent that text rendering is no longer a performance issue, and the resulting text looks smooth and can be scaled as much as the TrueType font permits. I also modify the texture in other ways before it's uploaded, to create things like drop shadows.
At one point I did the whole UI by CPU using AntiGrain and then cached the textures for fast rendering. Pretty good tradeoff between performance and looks.
vBulletin v3.6.0, Copyright ©2000-2008, Jelsoft Enterprises Ltd.