I have a D3D 11 application to which I would like to add support for software rendering. This is because in some circumstances it will be run on over remote desktop or on machines without GPUs. From the research I have done, it seems like my best bet is WARP.

It was surprisingly simple to change the app to use WARP:

hr = D3D11CreateDevice(

It runs nicely. Where I'm struggling is determining when to set the driver type to WARP instead of hardware. Is there a function I can call that will tell me if hardware support is available on the system?

I'm using D3D 11 with the 9_1 feature level.

  • \$\begingroup\$ You could try to create the device using DRIVER_TYPE_HARDWARE, then if it fails, fall back to DRIVER_TYPE_WARP. \$\endgroup\$ Feb 10, 2014 at 22:40
  • 1
    \$\begingroup\$ @fatcat1111: it's not an abuse, it's intended use of APIs like these. Try each choice in order until one works. It's similar to providing multiple feature levels, except those are explicitly part of the API because of "reasons." \$\endgroup\$ Feb 11, 2014 at 1:59

1 Answer 1


The proper way to determine if you can create a device of a particular type (hardware / software) with particular feature levels is to attempt to create a device with the options you want, and if that fails, fall back to a less-featured device. The documentation demonstrates this technique for feature level fallbacks, and you can apply a similar one for trying hardware versus WARP devices.

Note that this is not an "abuse of exceptions as flow control," per your comment, because D3D does not throw (C++) exceptions (being a COM API, which needs to run in C, it cannot). Failure to construct a device just returns a result code indicating that failure, and this is mechanically no different than checking the result of a "do I support hardware devices?" function.

Further, this technique is actually better since it eliminates a potential (although rare in practice in D3D's case) race condition: if you have a pair of functions, one for querying the available functionality and another for initializing said functionality, there is a period of time between the query call and the initialize call when the functionality could, for some reason, become unavailable. So you need to be checking the result of the initialize call anyway, therefore the first call is just redundant.


You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .