Sign in to follow this  
RobMaddison

DirectX Pipeline

Recommended Posts

RobMaddison    1151
Following on from a post regarding locking/drawing from dynamic vertex buffers I posted recently, I read a bit more about the architecture of DirectX and how things 'should' be done (which I should have done ages ago and would recommend to anyone). I'm a bit confused though, on something that should probably be glaringly obvious: Imagine this scenario: 1) for i = 0; i < 20; i++ 2) device->Clear(...) 3) rotate camera 18 degrees on y axis 4) carry out intensive DIP calls to draw the scene 5) device->Present(...) (flushes command buffers, etc.) The CPU is running pretty fast through this and due to the asynchronous nature of the GPU, that is running at its own pace carrying out the instructions that the d3d runtime gives it (ignoring command buffers, mode transitions, etc. at this point to keep it simple to explain). My question is that if the GPU is drawing some intense geometry and takes a while to draw a frame, the CPU has happily got to the end of the loop and is back at step 1. If the GPU is still drawing, what happens when device->Clear() is called? Is it queued up and the CPU blocked? If not, surely if the CPU loop is much faster than the GPU can draw, something's got to give. Are frames skipped in this scenario? If step 3 involved say moving the camera around the y axis 20 times at 18 degrees each and the DIP calls were very GPU intensive, would any of the frames be skipped. When the CPU had finished 20 loops of 1-5, would the GPU have to catch up 5 frames if it was still on, say, frame 15 when the CPU had finished? I guess my ultimate question is if the GPU is chugging, surely the CPU must have to wait for it at some point? If you can't explicitly tell when the GPU has finished actually physically rendering, how can systems possibly keep frame rates smooth over different CPUs and Video cards. I know you can tell when the command buffer is empty, but the GPU still has to physically draw what it needs to. If anyone can point me in the direction of a decent doc on this, I'd really appreciate it. Thanks

Share this post


Link to post
Share on other sites
jollyjeffers    1570
Frames aren't ever skipped - there's a cap (usually ~3 frames) that the CPU can get ahead of the GPU on. Once it gets too far ahead (or the command buffer fills up) then calls into the API start blocking and it'll stall the application. Typically this happens in Present() calls.

You can use queries to force a pipeline stall if you really want to have finer control, but that's not a standard or recommended technique for production code.

hth
Jack

Share this post


Link to post
Share on other sites
RobMaddison    1151
I see. So say if that 360 turn should take exactly 3 seconds (or some other linear measurement that should be the same regardless of frame speed) and you're running on a low-end video card, you might have to miss some frames.

How can you tell when the video card can't keep up and you need to miss frames? I know framerate synchronization is probably a topic worthy of its own book, but I'm just trying to get a feel for the work I need to do.

Thanks

Share this post


Link to post
Share on other sites
jollyjeffers    1570
Well you really need to be expressing things in actual time rather than in frames. Time based modelling avoids the issue that you're hinting at - define a 360o rotation as taking 5 seconds. If you're rendering at 60hz then you rotate by 1.2o each frame, on a low end system at 15hz then you rotate by 4.8o degrees per frame. In a way it's sort of like dropping frames, but much more elegant [smile]

Jack

Share this post


Link to post
Share on other sites
sirob    1181
You normally don't assume you have a fixed time step. That is, you don't assume that you'll be running at X frames per second. Instead, you use timing calls to obtain the current time, and calculate how much time has passed since your last update. Using this time, you can then, for example, turn an object by (360 degrees / 3 seconds * amount of time passed since last frame). This kind of calculation makes sure the object rotates 360 degrees ones every 3 seconds regardless of whether your FPS is 10 or 10000.

Hope this helps.

Share this post


Link to post
Share on other sites
RobMaddison    1151
Hi

Quote:
You normally don't assume you have a fixed time step. That is, you don't assume that you'll be running at X frames per second. Instead, you use timing calls to obtain the current time, and calculate how much time has passed since your last update. Using this time, you can then, for example, turn an object by (360 degrees / 3 seconds * amount of time passed since last frame). This kind of calculation makes sure the object rotates 360 degrees ones every 3 seconds regardless of whether your FPS is 10 or 10000.


If you have no way of telling exactly when the video card has physically finished drawing what's in the command buffer, how can you calibrate the time that has passed?

Thanks

Share this post


Link to post
Share on other sites
jollyjeffers    1570
Quote:
Original post by RobMaddison
If you have no way of telling exactly when the video card has physically finished drawing what's in the command buffer, how can you calibrate the time that has passed?
It's usually acceptable enough to just time based on when the application submits the Draw() operation.

hth
Jack

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this