A SharpDX interop library for ILGPU
A SharpDX interop library for ILGPU
Many 3D applications often rely on compute shaders to implement computer graphics or advanced simulation algorithms. Using ILGPU to implement advanced algorithms in 3D applications can simplify these tasks. This interop library provides access to native Direct3D (11.X) resources (compute buffers or textures) from ILGPU. The ILGPU SharpDX Interop library is released under the University of Illinois/NCSA Open Source License.
Please note that SharpDX is an independent project that is not related to the ILGPU project.
Write ILGPU kernels that can access your Direct3D 11.X resources from SharpDX.
Buffers and Textures that are created via the provided interop accelerator can be accessed from your ILGPU kernels.
As always, all kernels can be run and debugged with the CPU accelerator. Note that your Direct3D 11.X device does not need to be in software emulation mode.
The new interop library supports .Net Core 2.0, .Net 4.7 and the latest SharpDX release. This simplifies integration into many different applications. Furthermore, it supports the new ILGPU compiler.
Typically, you create a Direct3D device somewhere in your application. It usually looks like that:
using SharpDX; using SharpDX.Direct3D11; ... Device.CreateWithSwapChain( DriverType.Hardware, DeviceCreationFlags.Debug, swapChainDescription, out Device device, out SwapChain swapChain);
After you have created the device, you can setup an Associated Accelerator in the ILGPU world.
The instantiated accelerator "knows" the associated Direct3D device and activates general interop support.
Currently, you can chose between AcceleratorType.Cuda
or AcceleratorType.CPU
.
using ILGPU; using ILGPU.SharpDX; ... ilgpuContext = new Context(); accelerator = device.CreateAssociatedAccelerator(ilgpuContext, AcceleratorType.Cuda);
To create and manage Direct3D objects, we need to create an Interop Accelerator Note that the Interop Accelerator will be removed in future releases to simplify programming. Instead, all operations will be performed on the Associated Accelerator in future versions.
interopAccelerator = accelerator.CreateDirectXInteropAccelerator(device); // Create a buffer that stores vertex information with 6 elements. vertexBuffer = interopAccelerator.CreateBuffer<MyVertexStruct>(6, DirectXBufferFlags.None); // Create a texture with width = 640, height = 480 and format = Vector4 colorTexture = interopAccelerator.CreateTexture2D(640, 480, Format.R32G32B32A32_Float);
Note that you have to dispose all buffers and textures before you can dispose the Interop Accelerator. You can then safely dispose the Associated Accelerator and the global ILGPU context.
Before buffers and textures can be used from ILGPU kernels, they have to be mapped. After you have completed all operations on the ILGPU side, you must release the mapped resources. This ensures that all ILGPU operations are finished and that the graphics API can access the mapped buffers again.
using (var mapping = interopAccelerator.MapBuffer( dxIntermediateContext, vertexBuffer, colorTexture)) { // ILGPU operations... } // Graphics operations...
Although the returned DirectXBufferMapping
object is a structure, it implements the IDisposable
interface.
This allows the programmer to use using
statements to ensure that the required Unmap
operation is called automatically.
If you cannot (or do not want to) use a using
statement, you have to call Unmap
manually.
var mapping = interopAccelerator.MapBuffers( dxIntermediateContext, vertexBuffer, colorTexture); // ILGPU operations... mapping.Unmap(); // Graphics operations...
Note that the mapping operation is a time-consuming step and should only be called once per frame.
It is time-consuming since it ensures that all calls to the graphics API are completed before a kernel launch is triggered.
Try to batch all buffers you need and map them in a single step (for example, at the beginning of your simulation loop).
Pay additional attention to the last parameter of the Map
function.
It is a parameter array that causes an additional array creation upon invocation.
Try to store your arguments to a pre-allocated array in order to avoid additional heap allocations in your render loop.