Plugin access to the active ID3D11Device in Rhino 9

Hello McNeel team,

First of all, congratulations for the OpenGL → Direct3D migration in Rhino 9.

I am developing a Grasshopper plugin which performs GPU spatial analysis with CUDA/OptiX and displays the results in the viewport through GPU interop. For this to work efficiently (zero-copy resources, no host round-trip), the plugin needs to access the same graphics device that Rhino itself uses for its display engine.

In Rhino 8, this was implicit: inside a DisplayConduit callback, the OpenGL context was already current on the calling thread, and any GL call would naturally target it. We could register VBOs with CUDA through cudaGraphicsGLRegisterBuffer without ever needing an explicit handle.

With Direct3D 11, this implicit model no longer applies — plugins need an actual ID3D11Device pointer to share resources with Rhino’s renderer. And as far as I can see, the public SDK does not currently expose it: neither RhinoCommon nor the C++ headers offer a documented way to retrieve the active device.

Would it be possible to envisage a public accessor for this? Even a minimal one returning ID3D11Device* (and ideally the immediate context) would restore for D3D11 plugins what was naturally available in Rhino 8.

If this is already planned, would you have an approximate idea of when it might land — even just “Rhino 9 release” vs “a later service release” would help me plan accordingly. And of course, if I have missed an existing mechanism, I would be grateful for a pointer.

I remain available to share more details about the use case if needed.

Thank you for your time, and have a good week ahead.

Laurent-Emmanuel

Pinging @stevebaer in case this is in your area — happy to move it elsewhere if there’s a better place to ask.

We don’t expose this yet, but it wouldn’t be hard. Do you need this in C++ or .NET?

Hello @stevebaer, thank you so much for the quick reply — and even more for being open to exposing it.
Ideally both, but C++ would be the more valuable one to prioritize. The actual consumer of the ID3D11Device* in my plugin is cudaGraphicsD3D11RegisterResource, called from a native DLL (CUDA/OptiX) that does all the GPU work. A C++ SDK accessor would let that native code obtain the device directly, with no marshalling, no opaque pointer crossing the managed boundary, and no ambiguity about COM lifetime. It’s architecturally the cleanest path, and I imagine most plugins doing GPU interop are in a similar situation — the .NET side is mostly orchestration, the heavy lifting lives in native code.
A .NET accessor (returning an IntPtr that can be P/Invoked downstream) would also be welcome as a convenience for plugins that don’t have a C++ component, and since RhinoCommon typically wraps the C++ SDK through rhcommon_c anyway, it would follow naturally once the C++ side exists.
If you also expose the ID3D11DeviceContext* (or even just hint at how to obtain it — device->GetImmediateContext() is fine if there are no threading concerns on your side), that would round things out nicely.
Happy to test any preview build whenever it lands.
Thanks again!

Hi @stevebaer — apologies, I got a bit carried away with my last reply!

No rush at all — just one quick question whenever it’s convenient: is a C++ accessor for the active ID3D11Device* more of a “Rhino 9 release” thing, or a later service release? A rough idea is plenty.

Thank you again for being open to this, and have a good week.

I have added the following 2 functions to CRhinoDisplayPipeline in the C++ SDK. These will be available when we release a C++ SDK for Rhino 9. This will happen before we ship Rhino 9.

  // Description:
  //  If the pipeline is running on top of Direct3d 11, this function
  //  will return the ID3D11Device* being used. nullptr will be returned
  //  if the pipeline is running on some other GPU technology.
  //  NOTE: AddRef is NOT called on this IUnknown instance
  struct ID3D11Device* GetDirect3d11Device();
  // Description:
  //  If the pipeline is running on top of Direct3d 11, this function
  //  will return the ID3D11DeviceContext* actively being used.
  //  nullptr will be returned if the pipeline is running on some other
  //  GPU technology.
  //  NOTE: AddRef is NOT called on this IUnknown instance
  struct ID3D11DeviceContext1* GetDirect3d11DeviceContext();

Hi @stevebaer — this is wonderful news, thank you so much! Really made my week. I’ll wire it in the moment the C++ SDK preview lands. Thank you again!