This is a guidance document to help game developers port their existing D3D12 games from Windows 10 to Windows 7. The current draft is based on the latest D3D12 runtime bits (“Microsoft.Direct3D.D3D12On184.108.40.206.nupkg”). Please read through this guidance document before your planning.
If game developers have D3D12 games already running on Windows 10, they can port those games to Windows 7 with expectation of small code churn, mostly feature parity, reasonable performance, and a short list of limitations.
… with SDK Layer clean of errors or warnings.
Most of the files below will be included and distributed in a single nupkg.
Download recent Windows 7 drivers from GPU vendors.
Dev machines: You can continue to develop and build your Windows 7 SKU on your Windows 10 dev machine using matching Windows 10 SDK. Optionally, you can set up a dev machine to enable the Windows 7 emulation mode using the Windows 10 debug layer (see “Run Windows 10 SDK Layer in Windows 7 emulation mode” below);
Test machines: Set up a PC with Windows 7 SP1 (Windows version number 7601) for local testing.
We only ported the D3D12 runtime to Windows 7. Therefore, the difference of Graphics Kernel found on Windows 7 still requires some game code changes, mainly around the presentation code path, use of monitored fences, and memory residency management (all of which will be detailed below). Early adopters reported from a few days to two weeks of work to have their D3D12 games up and running on Windows 7, though the actual engineering work required for your game may vary.
You can continue to use the Windows 10 dev machines to build the Windows 7 EXE.
To reduce confusion about various DLLs that might reside on a gamer’s machine, developers should load D3D12.dll in the following way.
HMODULE hD3D12 = LoadLibraryA("12on7\\d3d12.dll");
hD3D12 = LoadLibraryA("d3d12.dll");
Once D3D12.dll is loaded, you can either use
DelayLoad linking to retrieve functions from the DLL. Note that you cannot use static linking against d3d12.lib. Apps do not need to explicitly load dxilconv7.dll, and should only load d3d11on12.dll when running on Windows 7 (loading 12on7\d3d12.dll succeeded).
We recommend runtime checking in your code as follows.
// For Windows 7
// For Windows 10
D3D12 on Windows 7 requires different Present APIs. Specifically, attempting to create a DXGI swapchain on a D3D12 device or queue will fail on Windows 7, because DXGI is not updated as part of this package.
As an alternative, you should use
ID3D12CommandQueueDownlevel::Present. Note that this API only supports windowed blt presents, not fullscreen exclusive or any other mode. The application is responsible for window management, this API will not send messages nor manipulate window properties in any way. The resource that the application provides should not be multisampled, must be committed, and must be in a “displayable” format, one of the following:
The same D3D12 fence APIs behave mostly the same as on Windows 7, except no support for fence rewinding (signaling to a lower value, after a higher value signal has been queued) or out-of-order fence waits (waiting for a value whose signal has not yet been queued).
Please follow the instructions in “Run Windows 10 SDK Layer in Windows 7 emulation mode” to identify usage of unsupported fence usage patterns. Then you can refer to the updated public residency helper library (d3dx12residency.h) and see how you can remove those patterns. This also helps for ongoing QA testing to catch issues specific to Windows 7.
Since DXGI is not updated,
IDXGIAdapter3::QueryVideoMemoryInfo is not available. Instead, the application should use
ID3D12DeviceDownlevel::QueryVideoMemoryInfo. Also, be aware that the existing public residency helper library (d3dx12residency.h) has been updated to use this new API and to remove monitored fence usages when running on Windows 7.
ID3D12Device::Evict and resource destruction are synchronous operations on Windows 10, meaning that all work referencing that resource must be complete, these are queued operations on Windows 7. The app may want to take advantage of this to reduce the number of resident resources at work submission time, to improve performance. See below.
Please refer to “Q: Do you support all D3D12 features on Windows 7?” and “Q: What limitations should I expect when porting D3D12 games to Windows 7?” for unsupported features and add fallback solutions properly.
We added a new flag in Windows 10 SDK Layer to detect features not supported on Windows 7, primarily invalid fence usage patterns (e.g. fence rewinding, out-of-order fence waits).
To utilize this extra checking, developers need to set up a dev machine using Windows 10 May 2019 Update and the matching SDK (both with version number 18362), then call
ID3D12DebugDevice1::SetDebugParameter, with type
D3D12_DEBUG_DEVICE_PARAMETER_FEATURE_FLAGS, and value of
D3D12_DEBUG_FEATURE_EMULATE_WINDOWS7, available in the new “d3d12sdklayers.h” file. Note that there are some “false positive” errors with this validation in the May 2019 build, which are fixed in more recent Windows Insider builds.
Note that, you can continue to use your current SDK on Windows 10 machines to build the executable as long as you include the extra header file while compiling and you copy the down-level DLLs next to the output executable for use when it is run on Windows 7.
If your game is using D3D11On12, you need the files of D3D11On12On7.h and d3d11on12.dll, plus all the following code changes in the Windows 7 code path of your game.
If you plan to ship your D3D12 games on Windows 7 via Steam but your game does not directly use D3D11On12, you should perform step 1 only, because the Steam client uses D3D11on12 to render its overlay, and requires the DLL to be loaded by the application in order to work.
LoadLibrary on d3d11on12.dll.
GetD3D11On12On7Interface and call it to get
SetThreadDeviceCreationParams with your device and queue that you will be using, just as you would call
D3D11On12CreateDevice for Windows 10 usage.
D3D_DRIVER_TYPE_SOFTWARE, and pass the
HMODULE to d3d11on12.dll. This will return a D3D11On12 device that will submit work to your D3D12 device and queue you provided. If you did not call the
SetThreadDeviceCreationParams, this will attempt to create a new D3D12 device on the default adapter. This object does not expose
ID3D11On12Device like it does on Windows 10: that is implemented by d3d11.dll, which is not changing as part of D3D12 on Windows 7.
ID3D11On12On7::GetThreadLastCreatedDevice() to get an interface that you can use for interop.
ID3D11On12Device::CreateWrappedResource, you will call
ID3D11On12On7::SetThreadResourceCreationParams with your D3D12 resource, and then call the appropriate D3D11 create method (i.e.
ID3D11Device::CreateTexture2D). There will not be validation in place that your D3D11 and D3D12 creation parameters match, so make sure they do, or you will probably get some weird problems. Then you can call
ID3D11On12On7::GetThreadLastCreatedResource() to get an interface you can use for interop on that resource.
ID3D11On12Device::Acquire/ReleaseWrappedResources, you will call
ID3D11On127Device::Acquire/ReleaseResource. These have similar semantics, but it’s important to be aware that on Windows 10, the acquire/release APIs will prevent you from using the resource in D3D11 while it is released, but on Windows 7 the D3D11 runtime is oblivious to these “extensions” and will not help you out there.
If you are using middleware for rendering and find it broken on Windows 7, please let us know.
We encourage game developers to collect CPU performance data (using profiling tools) and GPU performance data (using timestamp) from D3D12 games running on Windows 7 and share those data with us and with GPU vendors. Doing so will allow all parties to better collaborate on identifying and addressing performance issues.
ID3D12PipelineLibrary to cache PSO
The story around automatic caching of shaders and PSOs is different on Windows 7. Specifically, the only caches present are those implemented within the IHV driver, and those explicitly done by the app using
ID3D12PipelineLibrary; there is no OS affordances for automatically caching. That means that if the driver does not have a cache present, or if the app provides DXBC shader code (i.e. shader model 5.1 or less, not 6) to the runtime, there will be overhead during PSO creation that can be removed by utilizing
ID3D12PipelineLibrary. Therefore, we highly recommend utilizing the
ID3D12PipelineLibrary APIs to make sure you are not getting unnecessary overhead.
If you find
ExecuteCommandLists substantially more expensive compared to Windows 10, it has to do with how many resources you have resident at the time of the call: On WDDM1.x (as found on Windows 7), the driver is responsible for submitting allocation lists with ever command buffer submission, which the kernel will iterate over and make sure they are resident before allowing that work to execute. In D3D12 on Windows 7, the driver generates this allocation list based on the set of resources that are currently resident at the time of submission. The cost you are seeing is a per-allocation cost, which can be quite high; the size of the allocation is irrelevant here.
To get that cost down, you have several options to reduce the number of resident resources,
Evict() to remove resources from residency when they are no longer in used. Games on Windows 7 can also call
Evict() or to destroy resources without waiting for resource usage to be finished (though the game does still need to wait before re-using those resources). Doing so will help cut down on how much is resident at any given time, because the WDDM1.x memory manager / scheduler on Windows 7 will ensure that those resources do not get evicted or destroyed before the last command buffer where they were referenced in the allocation list has finished. Note that, this is only an option on Windows 7; on Windows 10, game still need to wait for resource usage to be finished before calling
Evict() or destroying those resources.
To release your D3D12 games on Windows 7, you must package and release the Windows 7 version of D3D12 binaries as part of your game – gamers will not receive those binaries from Microsoft. Any update of those binaries (e.g. with bug fixes) will also be released to gamers as part of your game update, not from Microsoft.
Starting from nupkg 1.1.0 (released on 11/20/2019), we will switch binary signing from SHA-1 to SHA-2 in order to be compliant with Microsoft’s security policy, which may require Windows 7 gamers to install extra patches before they can install D3D12 binaries. Please see Q: Windows 7 gamers cannot install D3D12 binaires due to invalid digital signature? below for more details.
The app should not have two different EXEs and decide which EXE to install during installation time. The app must either (1) have one executable for both Windows 7 and Windows 10 (preferred), or (2) have two different EXEs but also have a single launcher to choose the right EXE at launch time.
See “Q: Can I build one single executable that works for both Windows 10 and Windows 7? And how?” below on how to build a single executable for both Windows 7 and Windows 10.
A: Yes. Game developers need to pay attention to the following,
When properly forked, the executable running on Windows 10 should not suffer from any feature limitation or performance loss.
A: The current runtime supports D3D12 features as released in Windows 10 October 2018 Update (notably, DX Raytracing but not DirectML) on Windows 7.
To focus our support on key scenarios that most game developers care about, our current support for D3D12 on Windows 7 has the following limitations. Please review during your planning and have fallback plans in place.
CreateSharedHandle do not work
A: HDR support is orthogonal to D3D12 and requires DXGI/Kernel/DWM functionalities on Windows 10 but not on Windows 7.
A: You can continue to use your current SDK on Windows 10 machines to build the executable as long as you include the extra header file when compiling and you copy the down-level DLLs next to your Windows 7 executable (see “Set up your project” above).
If you want to run the SDK Layer to detect (1) unsupported flags like sharing, and (2) invalid fence usage patterns (e.g. fence rewinding, out-of-order fence waits), you will need to move up to the latest Windows 10 and matching SDK. See “Run Windows 10 SDK Layer in Windows 7 emulation mode” for details.
A: D3D12 on Windows 7 will work the same way as on Windows 10: a simple query of feature level + tier is enough. D3D12 on Windows 7 does not introduce new tiers.
A: No. We explicitly fail the case where developers trying to load the Windows 7 version of D3D12.DLL on a Windows 10 machine. It will also fail even if one forces the game to run in Windows 7 Compatibility Mode. The Windows 7 version of D3D12.DLL can only be loaded and executed on Windows 7 SP1.
A: No, the Windows 7 version of D3D12.DLL can only be loaded and executed on Windows 7 SP1.
A: Starting from nupkg 1.1.0 (released on 11/20/2019), we will switch binary signing from SHA-1 to SHA-2 in order to be compliant with Microsoft’s security policy, which may require Windows 7 gamers to install extra patches before they can install D3D12 binaries.
To minimize interruption for your Windows 7 gamers, game developers should first decide if their game installer validates binary signing when deployed on Windows 7 PC then follow up properly.
A: Please post your questions at DirectX Discord.