   Poor 2D Direct3D performance
  I'm a bit perplexed that doing 2D stuff in Direct3D, I seem to be struggling to get the performance that I used to get with DirectDraw.I'm using an indexed vertex buffer, batching all my quads into one DrawIndexedPrimitive call, drawing all the sprites from the same texture and using a dynamic (D3DLOCK_DISCARD) vertex buffer.Yet I don't seem to be able to get more than a few hundred 32x32 quads on the screen before it starts getting all jerky. If I draw a large quad as a background it gets even worse.Weirdly, as an experiment I tried not batching all the quads, and drawing each individually with DrawIndexedPrimitive and it seemed to run at exactly the same speed as before, which made me wonder if I was doing something wrong.I've scrapped the code I had with a plan to start again so can't post it (less than helpful, I know) but I was just wondering if there was anything I was missing. My PC will happily run something like GTA3 or Deux Ex through Direct3D drivers and surely there must be thousands of polys being drawn per frame on them.   
  I think we probably need to see some code. All I can suggest is that you're not locking the vertex buffer properly, and that's causing the rendering pipeline to stall.A dynamic VB should be created with D3DUSAGE_DYNAMIC, and you should lock it once with D3DLOCK_DISCARD when you lock the start of the buffer, and then repeatedly with D3DLOCK_NOOVERWRITE until there's no space left, then you go back to D3DLOCK_DISCARD and continue.Are you locking the VB only once per frame? Do you have the debug runtimes installed? They quite often give hints when there's performance problems.   ;  Some issues I can think of:-Wrong setup of backbuffer and/or refresh rate-texture size wrong or too big-too many setTexture changes.   ;  Cheers. I'll have to come back with some code when I've rewritten it. Thought you'd say that. Fair enough.Evil Steve - what is all this about repeatedly locking with NO_OVERWRITE? I was just locking the VB once at the start of the frame, with LOCK_DISCARD, then filling it with quads, unlocking and drawing.Also, on the hardware I have described (500mhz P3, 64meg NVIDIA card) how many quads would you expect to be able to render while keeping above or around 60 fps?Otherwise, cheers for the input and I'll bump this thread after the weekend when I've re-written what I had before.Paul   ;Quote:Original post by EasilyConfusedEvil Steve - what is all this about repeatedly locking with NO_OVERWRITE? I was just locking the VB once at the start of the frame, with LOCK_DISCARD, then filling it with quads, unlocking and drawing.See "Using Dynamic Vertex and Index Buffers" in Performance Optimizations in the DirectX docs. Actually, locking constantly with DISCARD will work fine, but another way is to allocate a large vertex buffer and lock it in segments. When you run out of space, you use DISCARD and D3D can do some fancy stuff behind the scenes and lets it upload the data to the card while handing you back another memory buffer. If you're doing something like sprite rendering where you don't know exactly how many vertices you'll need to start with, this is the better bet.Quote:Original post by EasilyConfusedAlso, on the hardware I have described (500mhz P3, 64meg NVIDIA card) how many quads would you expect to be able to render while keeping above or around 60 fps?It's hard to say, but your CPU is probably going to be your limiting factor. What NVIDIA card exactly? There's a huge difference between a TNT2 and a GeForce 6...As Marmin said, what is your texture size, and how many calls are you making to the IDirect3DDevice9 (SetRenderState, SetStreamSource, SetTexture, etc) per frame? Are you fullscreen or windowed, and what size is your backbuffer?Overall, "A few hundred" 32x32 quads sounds about right for that setup. How on earth can you play GTA3 with that though?   ;  Re GTA3, I was quite amazed as well but at 640x480 with trails turned off, it runs like a dream. Weirdly, it also runs Tomb Raider: Angel of Darkness perfectly smoothly as well.I wouldn't believe it either if I hadn't seen it with my own eyes. Guess it must be a pretty good graphics card. Apparently it is an NVIDIA GeForce4 MX 4000 if that means anything to you.To be fair, 500mhz is the minimum specs on the cases of both games. Just goes to show.   ;Quote:Original post by EasilyConfusedRe GTA3, I was quite amazed as well but at 640x480 with trails turned off, it runs like a dream. Weirdly, it also runs Tomb Raider: Angel of Darkness perfectly smoothly as well.I wouldn't believe it either if I hadn't seen it with my own eyes. Guess it must be a pretty good graphics card. Apparently it is an NVIDIA GeForce4 MX 4000 if that means anything to you.To be fair, 500mhz is the minimum specs on the cases of both games. Just goes to show.I have more respect for GTA3 now [smile]The GeForce 4 MX is a reasonably powerful card, but the MX series of any GeForce is lower end than a non-MX version of the same card. It's still a fairly good card, and it should be fine with GTA3 (Although I'm still amazed at the CPU).Back to the performance in your app:Quote:As Marmin said, what is your texture size, and how many calls are you making to the IDirect3DDevice9 (SetRenderState, SetStreamSource, SetTexture, etc) per frame? Are you fullscreen or windowed, and what size is your backbuffer?If you're batching poorly, then it's entirely possible that you'll get a low frame rate. Submitting more than 200 batches / frame causes a 1GHz CPU to be used 100% just submitting batches, so you'll probably manage less than 100 / frame (Although someone around here (circlesoft?) snooped on GTA3 and found it submitting a crapload of batches - curious...)   ;  Don't forget to set the WRITEONLY flag on the vertex buffer, and lock only with READONLY. Though it shouldn't matter for locks with DISCARD, if you try a NOOVERWRITE without a READONLY flag, DX will grab the data from the buffer -- a slow and unneeded process.Also, while you're at it, give a MANAGED buffer a try. While it wouldn't provide optimal performance, if your system is very ineffecient in the way it locks/copies, a managed pool buffer would let you know you've still got "room to grow". Hope this helps.[Edited by - sirob on July 26, 2006 7:21:35 AM];Quote:Original post by sirobDon't forget to set the WRITEONLY flag on the vertex buffer, and lock only with READONLY. Though it shouldn't matter for locks with DISCARD, if you try a NOOVERWRITE without a READONLY flag, DX will grab the data from the buffer -- a slow and unneeded process.You shouldn't be locking with READONLY at all. If you need to read from a VB, store a system memory copy of it. Reading from pretty much any resource is slow as hell.   ;Quote:Original post by Evil SteveQuote:Original post by sirobDon't forget to set the WRITEONLY flag on the vertex buffer, and lock only with READONLY. Though it shouldn't matter for locks with DISCARD, if you try a NOOVERWRITE without a READONLY flag, DX will grab the data from the buffer -- a slow and unneeded process.You shouldn't be locking with READONLY at all. If you need to read from a VB, store a system memory copy of it. Reading from pretty much any resource is slow as hell.Yeah, not sure why I actually wrote that. You'd obviously not want to lock with READONLY. But the WRITEONLY flag should be used. Sorry 'bout any confusion caused...   