Jump to content
  • Advertisement
Sign in to follow this  
_void_

D3D 12: Using fence objects

This topic is 1138 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone,

I have started getting familiar with D3D 12.
I cannot really sort out from MSDN documentation how fence objects are used for synchronization.
I would like to ask you help me figure out the following in particular.

 

1.How do we specify in DX API that I am waiting for a particular command list to complete its execution.
In Mantle API when you submit a command list for execution, you can pass an associated fence object as well.
I cannot see in the documentation how you establish a relation between a command list and a fence object.

2.ID3D12CommandQueue::Signal()
The documentation states "Use this method to set a fence value from the GPU side".
What does this refer exactly to? From my understanding doing something from the GPU side means doing it from a shader.
Calling DX API function from the shader does not make any sense.

3.ID3D12CommandQueue::Wait() and Win API WaitForSingleObject()
As far as I understand, there are two ways to wait for a fence object to be signaled.
The first one is using ID3D12CommandQueue::Wait(). Another one is Win API Event object assigned to a fence object and WaitForSingleObject().
They seem to be doing the same thing or am I missing something? Could you please elaborate on an example for their difference in usage if there is.
In basic DX 12 app guide https://msdn.microsoft.com/en-us/library/windows/desktop/dn859356(v=vs.85).aspx they are bothering with WaitForSingleObject() for synchronization.

Why do not they use one ID3D12CommandQueue::Wait() call instead?

Many thanks in advance!

Share this post


Link to post
Share on other sites
Advertisement
A follow-up question-

Phantom covered GPU signals, GPU waits and CPU waits; is there also a way for the CPU to signal?

i.e. can we call CommandQueue::Wait() to make the GPU (potentially) stall, and then call a CPU side function to indicate that it's noe safe for the GPU to proceed?
This would be useful when using the CPU to generate data in a buffer, which a shader will consume.

Share this post


Link to post
Share on other sites

i.e. can we call CommandQueue::Wait() to make the GPU (potentially) stall, and then call a CPU side function to indicate that it's noe safe for the GPU to proceed?
This would be useful when using the CPU to generate data in a buffer, which a shader will consume.

Not to my knowledge. As far as I know this was wanted multiple times, but it requires a shader that never ends waiting for information coming from the CPU, whether in a busy loop, or with some sort of sleep mechanism.

Such thing would be one-way ticket to TDR.

Edited by Matias Goldberg

Share this post


Link to post
Share on other sites

i.e. can we call CommandQueue::Wait() to make the GPU (potentially) stall, and then call a CPU side function to indicate that it's noe safe for the GPU to proceed?
This would be useful when using the CPU to generate data in a buffer, which a shader will consume.

Not to my knowledge. As far as I know this was wanted multiple times, but it requires a shader that never ends waiting for information coming from the CPU, whether in a busy loop, or with some sort of sleep mechanism.
Such thing would be one-way ticket to TDR.

Having the GPU wait on a signal from the GPU has the same pitfalls, doesn't it? I can insert a Wait command and then fail to insert a corresponding Signal, dooming my queue to wait for eternity.

Share this post


Link to post
Share on other sites

Having the GPU wait on a signal from the GPU has the same pitfalls, doesn't it? I can insert a Wait command and then fail to insert a corresponding Signal, dooming my queue to wait for eternity.

Yes but no. Yes, it might produce a TDR. But the wait GPU-on-GPU command puts a fence on the hardware command queue, which is easy to recover from (just signal that fence and continue executing the queue or clear it), particularly in cases like abnormal process termination CPU side.
It is virtually no different from sending data from the CPU and adding a command to queue to run a shader that will use this data.

What you're asking is low latency (i.e. let the GPU see/wake the data right away) so it requires synchronization at the shader execution level. Either interrupting the shader to keep it in a "waiting/sleeping" list with all of its state saved somewhere, or a live spin checking for the data. I don't know if all supported hardware supports the former, and as for the latter, such live lock is really hard to get right.

 

Technically you can already do that livelock. Try it. It will work as long as the shader terminates at some point, before TDR happens. Then spawn it again. (or manually disable TDR in your machine and check what happens)

But it may not likely work or perform poorly in GPUs with just one hardware queue as the almost-never-ending shader will stall the next commands.

And all of that assuming you get the busy spin wait right and works reliably on all GPUs or at least a broad range of them.

Edited by Matias Goldberg

Share this post


Link to post
Share on other sites

Yes but no. Yes, it might produce a TDR. But the wait GPU-on-GPU command puts a fence on the hardware command queue, which is easy to recover from (just signal that fence and continue executing the queue or clear it), particularly in cases like abnormal process termination CPU side.

Why can't a CPU-signalled event also use a fence on the command queue in the exact same way? The GPU queue has a wait fence in it, which is cleared by the CPU. Why do you need a shader?? This is used all the time by console devs, but yeah, they don't have to worry about untested code crashing people's PC's!
 
[edit]
Nvm, ID3D12Fence::Signal is the CPU-side equivalent of ID3D12CommandQueue::Signal smile.png Turns out it is finally available in D3D12.

Edited by Hodgman

Share this post


Link to post
Share on other sites
Ah yes, I should have linked to the docs in my reply as the page for ID3D12CommandQueue::Signal has the remark;

Use this method to set a fence value from the GPU side. Use ID3D12Fence::Signal to set a fence from the CPU side.


And, as noted, it is for situations where a command queue has been queued but it is waiting for a CPU side operation to complete before it is safe to proceed (ex; filling an indirectexecute buffer with data before the GPU kicks the command).

Probably best used sparingly and as a safety net as you don't really want to have the GPU sat idle while the CPU pokes at things too often ;)

Share this post


Link to post
Share on other sites

Yeah, as with any CPU<->GPU communication points, you really don't want them to every actually hit your sync point and wait, or you'll likely instantly halve your framerate smile.png
 
On PC, we've traditionally run a rendering loop like:
Find visible objects
Update data for those objects (cbuffers, dynamic index buffers, CPU-skinned vertex buffers, etc, etc).
Issue draw calls for those objects
And then about a frame later, the GPU finally gets around to processing those draw calls.
 
In console land, we've often reversed that loop into:
Find visible objects
Issue fence (GPU wait)
Issue draw calls for those objects
Update data for those objects
Clear fence (CPU signal)
 
Because the GPU is running about a frame behind, generally it never waits on the fence, but you have to put it there just in case smile.png
This ordering lets you reduce latency, because your draw commands are finished much earlier in the frame, and is helpful for batching resource updates together.
This new D3D12 ability now lets us do the same style on PC cool.png

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!