• Advertisement
Sign in to follow this  

(D3D12) upload heap lifetimes and mapped data

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

Looking at all the D3D12 samples, the preferred practice for getting system memory data up to a committed GPU resource seems to be to use an upload heap as a staging resource. I have a few questions about how this works:

  1. In the samples, the upload heap is created in the D3D12_RESOURCE_STATE_GENERIC_READ state, whereas the destination resource is created in the D3D12_RESOURCE_STATE_COPY_DEST state. The documentation doesn't seem to be clear what D3D12_RESOURCE_STATE_GENERIC_READ means, but of the D3D12_RESOURCE_STATE_COPY_SOURCE state, it says: "The resource is used as the source in a copy operation. Subresources must be in this state when they are used as the source of copy operation, or a blt operation. This is a read-only state." What is the true difference between these two states?
  2. The upload heap is created at the beginning of the sample and then never released. I assume that one would use a fence to check when the upload heap is no longer being used for an action operation? How would the app know when this has happened? Would it have to insert a fence after the upload operation and then poll it on a regular basis until the fence is signaled, then release the upload heap?
  3. Instead of creating one big committed upload heap, it seems like a better approach might be to allocate one big heap and then allocate chunks out of it. I'm unsure of how you would handle said buffer filling up (it seems like block or allocate a new heap page are the two obvious options). Would one giant upload heap be a better design choice?

With regards to mapped buffers, it appears that in D3D12 it is safe to map a buffer for the lifetime of the application. Is that data being DMA'd across to the GPU? Or is the driver keeping a dedicated system memory buffer around. This seems the most convenient way to copy data over, so I'm unsure why it would be preferred to use an upload heap.

 

Thanks!

Edited by ZBethel

Share this post


Link to post
Share on other sites
Advertisement

1) If you look at D3D12_RESOURCE_STATE_GENERIC_READ in the header you'll see it's actually a combination of several of the other "read" flags, of which D3D12_RESOURCE_STATE_COPY_SOURCE is one. I don't think there would have been any harm in specifically targeting D3D12_RESOURCE_STATE_COPY_SOURCE for the initial state, but D3D12_RESOURCE_STATE_GENERIC_READ is fine too.

 

2) You can create a fence using CreateFence and using ID3D12CommandQueue::Signal you can request the queue signal the fence to some value after all pending copies have been completed. From the CPU you can then either use ID3D12Fence::GetCompletedValue or set up an Event to wait on using ID3D12Fence::SetEventOnCompletion. These are two methods by which you can confirm the pending copies are complete and you're free to free the upload heap. Polling once per frame seems like a sensible rate at which to check for the copies being complete.

 

3) How you manage your upload heap is up to you. I'm not really sure what the difference is between the two methods you describe. The easiest thing to do is to simply allocate an upload heap large enough for your worst-case in terms of amount of data you want to upload in a single frame. Alternatively you could allocate an upload heap for each transfer to VRAM and fence/delete the heap as appropriate. The latter would keep memory usage to a minimum but doesn't really improve your worst case. If for any reason you mis-predict your worst case and run out of space in your upload heap you could either block the CPU until the GPU is done copying (not ideal) or allocate another upload heap as an emergency.

 

You can certainly map a resource for the lifetime of the application, but assuming we're still talking about a resource in an UPLOAD heap, then any CPU writes are simply writing to system memory. The GPU is capable of reading directly from the upload heap in system memory. This is fine if your upload heap just contains some "one-shot" constants or a few vertices, but you wouldn't want to keep larger, more frequently used resources in system memory as the bandwidth available (and latency) is typically very poor. If the data is going to be read repeatedly it should really be copied by the GPU from the upload heap into a resource located in a DEFAULT heap after which the upload heap could be freed.

 

Upload heaps really serve two purposes in most applications. The first is to act as a rolling buffer for any data that's generated by the CPU on that frame but need not persist beyond the end of the frame. An example of this type of data might be shader constants. The second is to act as a staging resource for the upload of new persistent resources to a DEFAULT heap, examples of these are textures, vertex buffers and index buffers. The upload heap that serves as your per-frame transient data is probably going to be required every frame from startup to shutdown and so may want to be handled differently to the upload heap used to upload new resources.

Edited by ajmiles

Share this post


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

  • Advertisement