Developer, Former MVP, now at Microsoft - Best of 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013
An accelerator represents a "target" on which C++ AMP code can execute and where data can reside. Typically (but not necessarily) an accelerator is a GPU device. Accelerators are represented in C++ AMP as objects of the accelerator class.
For many scenarios, you do not need to obtain an accelerator object, since the runtime has a notion of a default accelerator, which is what it thinks is the best one in the system. Examples where you need to deal with accelerator objects are if you need to pick your own accelerator (based on your specific criteria), or if you need to use more than one accelerators from your app.
You can query and obtain a std::vector of all the accelerators on your system, which the runtime discovers on startup.
Beyond enumerating accelerators, you can also create one directly by passing to the constructor a system-wide unique path to a device if you know it (i.e. the “Device Instance Path” property for the device in Device Manager), e.g. accelerator acc(L"PCI\\VEN_1002&DEV_6898&SUBSYS_0B001002etc");
accelerator acc(L"PCI\\VEN_1002&DEV_6898&SUBSYS_0B001002etc");
There are some predefined strings (for predefined accelerators) that you can pass to the accelerator constructor (and there are corresponding constants for those on the accelerator class itself, so you don’t have to hardcode them every time). Examples are the following:
accelerator acc;
accelerator acc(accelerator::direct3d_ref);
accelerator acc(accelerator::direct3d_warp);
accelerator acc(accelerator::cpu_accelerator);
You can also create an accelerator by shallow copying another accelerator instance (via the corresponding constructor) or simply assigning it to another accelerator instance (via the operator overloading of =). Speaking of operator overloading, you can also compare (for equality and inequality) two accelerator objects between them to determine if they refer to the same underlying device.
Given an accelerator object, you can access its description, version, device path, size of dedicated memory in KB, whether it is some kind of emulator, whether it has a display attached, whether it supports double precision, and whether it was created with the debugging layer enabled for extensive error reporting.
Below is example code that accesses some of the properties; in your real code you'd probably be checking one or more of them in order to pick an accelerator (or check that the default one is good enough for your specific workload):
vector<accelerator> accs = accelerator::get_all(); std::for_each(accs.begin(), accs.end(), [] (accelerator acc) { std::wcout << "New accelerator: " << acc.description << std::endl; std::wcout << "device_path = " << acc.device_path << std::endl; std::wcout << "version = " << (acc.version >> 16) << '.' << (acc.version & 0xFFFF) << std::endl; std::wcout << "dedicated_memory = " << acc.dedicated_memory << " KB" << std::endl; std::wcout << "doubles = " << ((acc.supports_double_precision) ? "true" : "false") << std::endl; std::wcout << "limited_doubles = " << ((acc.supports_limited_double_precision) ? "true" : "false") << std::endl; std::wcout << "has_display = " << ((acc.has_display) ? "true" : "false") << std::endl; std::wcout << "is_emulated = " << ((acc.is_emulated) ? "true" : "false") << std::endl; std::wcout << "is_debug = " << ((acc.is_debug) ? "true" : "false") << std::endl; std::cout << std::endl; });
In my next blog post I'll cover a related class: accelerator_view. Suffice to say here that each accelerator may have from 1..n related accelerator_view objects. You can get the accelerator_view from an accelerator via the default_view property, or create new ones by invoking the create_view method that creates an accelerator_view object for you (by also accepting a queuing_mode enum value of queuing_mode_automatic or queuing_mode_immediate that we'll also explore in the next blog post).