Direct3D 11 on 12 Updates
It’s been quite a while since we last talked about D3D11On12, which enables incremental porting of an application from D3D11 to D3D12 by allowing developers to use D3D11 interfaces and objects to drive the D3D12 API. Since that time, there’s been quite a few changes, and I’d like to touch upon some things that you can expect when you use D3D11On12 on more recent versions of Windows.
Lifting of limitations
When it first shipped, D3D11On12 had two API-visible limitations:
- Shader interfaces / class instances / class linkages were unimplemented. As of the Windows 10 1809 update, this limitation has been mostly lifted. As long as D3D11On12 is running on a driver that supports Shader Model 6.0 or newer, then it can run shaders that use interfaces.
- Swapchains were not supported on D3D11On12 devices. As of the Windows 10 1803 update, this limitation is gone.
We’ve made several improvements to this component’s performance. We’ve reduced the amount of CPU overhead significantly, and added multithreading capabilities to be more in line with a standard D3D11 driver. That means that the thread which is calling D3D11 APIs should see reduced overhead, but it does mean that D3D11On12 may end up competing with other application threads for CPU time. As with a standard D3D11 driver, this multithreading can be disabled using the D3D11_CREATE_DEVICE_PREVENT_INTERNAL_THREADING_OPTIMIZATIONS flag. However even when this flag is set, D3D11On12 will still use multiple threads to offload PSO creation, so that the PSOs will be ready by the time it is actually recording the command lists which use them.
Note that there still may be memory overhead, and D3D11On12 doesn’t currently respect the IDXGIDevice3::Trim API.
As of Windows 10 1809, D3D11On12 sets the D3D11_FEATURE_DATA_THREADING::DriverCommandLists flag. That means that deferred context API calls go straight to the D3D11On12 driver, which enables it to make ExecuteCommandList into a significantly more lightweight API when the multithreading functionality of D3D11On12 is leveraged. Additionally, it enables deferred contexts to directly allocate GPU-visible memory, and doesn’t require a second copy of uploaded data when executing the command lists.
On Windows 10 1809, when using PIX 1812.14 or newer, PIX will be able to capture the D3D12 calls made by D3D11On12 and show you what is happening under the covers, as well as enable capture of native D3D11 apps through the “force 11on12” mechanism. In upcoming versions of Windows, this functionality will continue to improve, adding PIX markers to the D3D11On12-inserted workloads.
A look in the D3D11On12 header will show ID3D11On12Device1 with a GetD3D12Device API, enabling for better interop between components which might be handed a D3D11 device, and want to leverage D3D12 instead. And in the next version of Windows (currently known as 19H1), we’re adding ID3D11On12Device2 with even better interop support. Here what’s new:
HRESULT UnwrapUnderlyingResource( _In_ ID3D11Resource *pResource11, _In_ ID3D12CommandQueue *pCommandQueue, REFIID riid, _COM_Outptr_ void **ppvResource12); HRESULT ReturnUnderlyingResource( _In_ ID3D11Resource *pResource11, UINT NumSync, _In_reads_(NumSync) UINT64 *pSignalValues, _In_reads_(NumSync) ID3D12Fence **ppFences);
With these APIs, an app can take resources created through the D3D11 APIs and use them in D3D12. When ‘unwrapping’ a D3D11-created resource, the app provides the command queue on which it plans to us the resource. The resource is transitioned to the COMMON state (if it wasn’t already there), and appropriate waits are inserted on the provided queue. When returning a resource, the app provides a set of fences and values whose completion indicates that the resource is back in the COMMON state and ready for D3D11On12 to consume.
Note that there are some restrictions on what can be unwrapped: no keyed mutex resources, no GDI-compatible resources, and no buffers. However, you can use these APIs to unwrap resources created through the CreateWrappedResource API, and you can use these APIs to unwrap swapchain buffers, as long as you return them to D3D11On12 before calling Present.