Jump to content
  • Advertisement
Sign in to follow this  
Funkymunky

[D3D12] Unmap resource while command list is being recorded

This topic is 619 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

Say I have a simple frame is set up as follows:

ID3D12CommandAllocator::Reset

ID3D12GraphicsCommandList::Reset

ID3D12Resource::Map  <- this is for a cbuffer

[ copy a new matrix to the mapped pointer for the cbuffer ]

ID3D12Resource::Unmap

[ submit draw calls ]

ID3D12GraphicsCommandList::Close

ID3D12CommandQueue::ExecuteCommandLists

 

Is there any problem with mapping/unmapping that buffer while the command list is being recorded?  The page on Unmap says "Unmap also flushes the CPU cache, when necessary, so that GPU reads to this address reflect any modifications made by the CPU."  I am seeing some weird behaviour when I update the buffer in this manner (single frames where objects jump around), and I don't if I move the map/memcpy/unmap to before the Resets.  But I'm confused, because I would think that the GPU won't try to access that data until after the call to ExecuteCommandLists.

Share this post


Link to post
Share on other sites
Advertisement

Are you synchronizing so that the previous frame is done reading from that cbuffer before you do the memcpy?

 

In general, mapping/unmapping does pretty much nothing on most architectures other than return a pointer, so the memcpy is the interesting thing going on here. And the memcpy should have no interaction with recording of the command list, just the execution.

Share this post


Link to post
Share on other sites

But I'm confused, because I would think that the GPU won't try to access that data until after the call to ExecuteCommandLists.
That is true.  But have you used this same buffer to store data for previous calls to ExecuteCommandLists?

Share this post


Link to post
Share on other sites

Huh.  So at the end of each frame (after all command lists have been submitted), I signal a fence. (via D3D12CommandQueue::Signal)  At the beginning of a frame I wait on that previously signaled fence (via ID3D12Fence::SetEventOnComplete and WaitForSingleObject).  The memcpy of new data won't take effect until the ID3D12CommandQueue has reached the end of the commands for that previous frame.

 

So my original understanding was correct; mapping/unmapping the buffer while recording a command list should be fine.  Which means I have an issue elsewhere.

Edited by Funkymunky

Share this post


Link to post
Share on other sites

So my original understanding was correct; mapping/unmapping the buffer while recording a command list should be fine.

Yes, you just have to make sure not to map/upmap a resource while the GPU is executing a command list that references that resource. 

at the end of each frame (after all command lists have been submitted), I signal a fence. (via D3D12CommandQueue::Signal)  At the beginning of a frame I wait on that previously signaled fence (via ID3D12Fence::SetEventOnComplete and WaitForSingleObject).

Note that this should work fine, but will give seriously reduced performance compared to a typical D3D11/GL application. This means that the CPU submits a batch of work to the GPU and then has to sit around and wait for the GPU to finish executing that work before the CPU begins to prepare the next frame. Likewise the GPU is sitting around idle waiting for each frame to be delivered by the CPU.
To get ideal performance, you need the CPU and GPU work to overlap, so the CPU is preparing frame N+1 or N+2 while the GPU is executing frame N. ... but doing so means that resource management is suddenly a much harder problem, as the GPU will always be working with the resource that you've given it.

Edited by Hodgman

Share this post


Link to post
Share on other sites

So my original understanding was correct; mapping/unmapping the buffer while recording a command list should be fine.  Which means I have an issue elsewhere.


As Hodgman says, you have to make sure you aren't reusing a buffer which is already being referenced/used by the GPU - it sounds like you are reusing a buffer which is currently being referenced by the GPU in some way; in this case a single constant buffer which you are updating each frame rather than having N-buffers or a large buffer which you only use a segment of each frame (which might be the best way to go).

Share this post


Link to post
Share on other sites
Oh I am rendering N frames. I also have N fences, that I check before updating the data used in a frame, precisely for the purpose of not updating a buffer while the GPU is using it.

Share this post


Link to post
Share on other sites
Ok, so do you associate the buffer with the upcoming fence somehow, and stall the CPU right before calling map until that fence has been completed?
i.e. how are you ensuring that the resource isn't in use by the GPU when you map it? Do you have a ring/double buffer of resources?

Share this post


Link to post
Share on other sites

Yes, every "buffer" is really N buffers under the hood, so each frame does this:

  • wait for fence N, if necessary
  • update buffer N
  • submit command list
  • signal fence N

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!