Interoperability between Direct 3D and C++ AMP

Hi, I am Charles Fu, a developer on the C++ AMP team. In this blog post, I will describe the C++ AMP Direct3D interoperability APIs. In my next blog post I will demonstrate how to build a simple DirectX 3D application, which renders the rotation animation of a 2D triangle.

To explore the easy programmability of C++ AMP for compute and the rich set of DirectX 3D APIs on graphic rendering, C++ AMP provides four interoperability APIs in the concurrency::direct3d namespace, which enable the sharing of D3D device and D3D buffer between C++ AMP code and D3D code. The creation of those resources can be either in the D3D code or in the C++ AMP code.

Here are the 4 APIs:

  • accelerator_view create_accelerator_view(IUnknown * _D3d_device_interface); Returns a newly created accelerator_view from an existing Direct3D device interface pointer.
  • template<typename T, int N> array<T,N> make_array(const extent &_Extent, const accelerator_view &_Rv, IUnknown * _D3d_buffer_interface) Creates an array with the specified extents on the specified accelerator_view from an existing Direct3D buffer interface pointer.
  • IUnknown* get_device(const accelerator_view &_Rv) Returns an IUnknown interface pointer corresponding to the D3D device underlying the passed accelerator_view.
  • template<size_t RANK, typename _Elem_type> IUnknown* get_buffer(const array<_Elem_type, RANK> &_F) Returns an IUnknown interface pointer corresponding to the D3D buffer underlying the passed array.

 

The first 2 APIs pass an existing D3D device or a D3D buffer to the C++ AMP code. They usually are created in the D3D code. To be consistent with the C++ AMP runtime system, they need to meet the following conditions:

  • The Direct3D device interface must support the ID3D11Device interface with a feature level D3D_FEATURE_LEVEL_11_0. Since C++ AMP allows concurrent submission of commands to an accelerator_view from multiple host threads, the Direct3D device should not be created with the D3D11_CREATE_DEVICE_SINGLETHREADED flag.

    The Direct3D buffer interface must support the ID3D11Buffer interface, and must be a STRUCTURED_BUFFER created with DEFAULT_USAGE and with a structure stride of 4 bytes in the VS11 Developer Preview (in the VS11 Beta, it must be a BYTEADDRESS_BUFFER) . It should allow SHADER_RESOURCE and UNORDERED_ACCESS binding. The buffer size in bytes must be equal to the size of (_Extent.size() * sizeof(_T)).The D3D device on which the buffer is created must be the same as that underlying the passing accelerator_view parameter.

The 3rd and the 4th APIs return an existing D3D device or a D3D buffer to the D3D code. You need to call the QueryInterface() on the returned IUnknown interface to get the correct ID3D11Device or the ID3D11Buffer interface pointer.

On failure, all the APIs throw a runtime_exception exception which is derived from std::exception. You can call the member function what() to query the error message.

After finished using the D3D resources, you need to call the Release() API to decrement the reference count on the interface object because the C++ AMP implicitly calls AddRef() on the underling resource in the interoperability APIs.

C++ AMP also supports interoperability with D3D textures using additional API in the concurrency::direct3d::graphics namespace . Read more at our blog post on Interop with Direct3D textures in C++ AMP.

I hope you can see how simple these APIs are. In the next post we’ll look at one example of using the APIs in my 2D Triangel Rotation sample.