2
\$\begingroup\$

In D3D10, I load a staging texture onto my GPU memory, then map it in order to access its texel data on the CPU. This is done on a separate thread, not the thread I render with. I just call the device methods, and it works.

In D3D11 I load the staging texture onto my GPU, but to access it (i.e. Map it) I need to use the Context, not the device. Can't use the immediate context, since the immediate context can only be used by a single thread at a time. But I also can't use a deferred context to Read from the texture to the CPU:

"If you call Map on a deferred context, you can only pass D3D11_MAP_WRITE_DISCARD, D3D11_MAP_WRITE_NO_OVERWRITE, or both to the MapType parameter. Other D3D11_MAP-typed values are not supported for a deferred context."

http://msdn.microsoft.com/en-us/library/ff476457.aspx

Ok, so what am I supposed to do now? It is common to use textures to store certain data (heightmaps for instance) and you obviously have to be able to access that data for it to be useful. Is there no way for me to do this in a separate thread with D3D11?

\$\endgroup\$
  • \$\begingroup\$ Deferred contexts are just recording data to command lists (as far as I know), then the immediate context executes the recorded commands. You could use a mutex to lock the immediate context and map to that, I think. By the way, you should not map textures, but set their shaderresourceviews to a shader slot. \$\endgroup\$ – János Turánszki Jan 28 '14 at 13:47
  • \$\begingroup\$ Hi! I want my CPU to access the texture data in a separate thread (something that btw worked just fine in D3D10). How would setting the texture's view to a shader slot help me with that? \$\endgroup\$ – user41464 Jan 28 '14 at 14:17
  • \$\begingroup\$ Code that "works" but has threading bugs can often not obviously manifest for a while. D3D has never been very multi-threaded friendly (and still isn't, even the "multithreaded rendering" that D3D11 purports to have is just command list recording, as noted above). \$\endgroup\$ – Josh Jan 28 '14 at 17:01
3
\$\begingroup\$

Once a texture is mapped to the CPU, its texel data is in CPU-accessible memory, which can be read by all threads, including your worker thread.

Thus, you should map the resource in your main thread using your immediate context, and then perform all your reads and assorted dependent work (which is generally where the real need for a worker thread would be) on a worker thread, setting some state or signal to notify the main thread when the worker is complete and the main thread can unmap the resource.

If map stall time (on the main thread) is an issue as well, consider the D3D11_MAP_FLAG_DO_NOT_WAIT flag (make sure to check if DXGI_ERROR_WAS_STILL_DRAWING is returned and then do something else if so).

To make the best use of this scenario, you're likely going to want to move as many post-read operations to the worker thread as you can (to load it), and also make sure you have other things the main thread can do if the resource is not mappable at the time (perhaps move on to another resource, for example) to make sure it stays loaded, otherwise there wasn't much point in multithreading the work.

\$\endgroup\$
  • \$\begingroup\$ Uh, ok, but the texture mapping is part of the loading function. One state is drawing while another state loads. Clean separation of tasks in a multithreaded environment. Now I need to somehow add the mapping code from one state to a completely unrelated part of my code because... duh D3D11 broke the multithreading ability D3D10 already had? \$\endgroup\$ – user41464 Jan 28 '14 at 17:13
  • 1
    \$\begingroup\$ As far as I am aware, D3D10 had no way to guarantee that behavior you are describing. It may have appeared to work but it was likely a ticking time bomb. D3D's "multithreaded" capability is basically supporting the recording of commands; not the execution. It does not (and has not) support "multithreaded rendering" or "multithreaded device access." \$\endgroup\$ – Josh Jan 28 '14 at 17:15
  • 1
    \$\begingroup\$ If you want clean separation of tasks, divorce them from D3D, which is synchronization point due to its API design and driver device access; for example, load your texture data off the disk without D3D and perform whatever post-map operations you want to do in a worker thread. When that is done, signal the main thread which creates a new texture with the until-now purely CPU-side data (or, in fact, just use the deferred context's Map and discard the whole existing buffer, splatting the new CPU-side memory into it). \$\endgroup\$ – Josh Jan 28 '14 at 17:18
  • \$\begingroup\$ "As far as I am aware, D3D10 had no way to guarantee that behavior you are describing." Sorry, but you are wrong. D3D10 internally locks the device whenever one of its method is called. Thus, my original D3D10 code, was 100% full proof. Now, if I want the equivalent behaviour in D3D11 I need to manually add locks whenever I use D3D11's context. Yeah, this is going to be fun...... It's messy, and its something D3D11 could have kept from D3D10 as an option to be as a flag in the device constructor. \$\endgroup\$ – user41464 Jan 28 '14 at 18:21
  • \$\begingroup\$ Anyway, thanks for taking the time to post. It's just frustrating finding yourself having to resort to 'messier' code when upgrading APIs. It should be the other way around! \$\endgroup\$ – user41464 Jan 28 '14 at 18:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.