03-06-09 - D3D Can Blow Me

Draw calls and state changes are *so* inefficient, that even a few hundred calls to draw debug overlay stuff cripples my performance. I'm working on my demo for GDC and I'm like drawing an earth model and paging 1.5 GB of textures, and it's all silky smooth perfect 100 fps. Then I add just a tiny bit of lazily written GUI drawing that makes a separate draw call for each character of a text string, and I'm at 40 fps. Urg. WTF.

Oh, and of course getting my damn text drawing to work takes like half a day because I write all the code, and of course nothing shows up. Of course there's some damn renderstate set that's messing it up.

If I was actually going to be writing a lot of D3D stuff I would write an entire wrapper of the whole damn thing that hid all the ugliness, and did things like let you just push individual triangles and it would gather them into batches for you. But of course as soon as I do that they'll rev the API again and it will change enough that all my work is for nought.


Ivan-Assen said...

Look at the (criminally obscurely named) ID3DXSprite and ID3DXFont interfaces for a reasonably efficient way of drawing UI with some kind of automatic batching.
Should be enough for demo purposes.

But yeah, you're right - our first revision UI system used a single draw call per UI primitive, and dominated the frame time for virtually nothing; we had to replace it with an ever growing monstrosity, which, however manages to draw almost always in a single drawcall.

cbloom said...

Hmm.. the reason I had to do this in the first place is that D3DXFont was so ungodly slow.

I've always just use D3DX in my simple demo apps because I think it's a very nice handy utility library, but D3DXFont was just destroying my frame rate.

It seems to be reasonably fast in window mode, but very slow in full screen. I guess that they are actually using GDI or something, locking the window bits and drawing directly into it. This is D3DX8 FWIW probably improved in newer versions.

Ivan-Assen said...

Look into it - some friends of mine were about to ship an actual retail PC game with an UI based on ID3DXSprite/ID3DXFont, and they're no idiots.

cbloom said...

Yep, a quick search indicates that

D3DXFont before "Dx9 summer update" was bad

D3DXFont after "Dx9 summer update" is good.

cbloom said...

Bleck. I need to get all my code up to a newer DX, but I'm not sure whether to just go to dx9 or wait a bit and jump to dx11. (I believe 10 is a no-go because it has poor support for low end hardware, but 11 is supposed to have better caps/compatibility support)

And I'll have to buy a new home computer. Sigh.

Ivan-Assen said...

Common sense (meaning the voices in my head) says: DX9 this year, DX11 next year.

Justin Paver said...

DX10 encapsulates related state into immutable objects that are validated at creation time. It removes a lot, but not all, of the state validation burden at draw-time (which is one of the main sources of draw-call overhead).

DX11 is basically incremental on DX10.1, but with TessellationShader, ComputeShader, Multithreaded driver support tacked onto a *very* similar API to DX10.

I.T.O API, it should be fairly easy to port between DX10 and DX11 so there's no real reason for delaying unless you want to target an OS other than Vista/Win7 or < DX10 feature level hardware.

cbloom said...

"unless you want to target an OS other than Vista/Win7 or < DX10 feature level hardware."

pretty crucial IMO.

Justin Paver said...

And your opinion is backed by stats. The DX10 gpu + Vista systems are only ~25% of those seen in the Steam hardware survey:


Of course if you target DX9 only now, you could be stuck with a codebase that gets old very quickly.

old rants