Jak używać interfejsu API D3D12GetDebugInterface z języka C #?

Sep 16 2020

Obecnie próbuję używać Direct3D z C # i zacząłem od korzystania z interfejsu API D3D12GetDebugInterface. Składnia funkcji w języku C ++ jest następująca (skopiowana z dokumentacji firmy Microsoft):

HRESULT D3D12GetDebugInterface(
    REFIID riid,
    void   **ppvDebug
);

Mam problem z zaimportowaniem funkcji do języka C #. Pomyślałem, że może riid powinno być wskaźnikiem do struktury Guid, a ja po prostu używam IntPtr dla ** ppvDebug. Ponieważ ** ppvDebug jest wskaźnikiem do wskaźnika do interfejsu ID3D12Debug, próbowałem ponownie zaimplementować interfejs ID3D12Debug w kodzie C # i użyć Marshal.PtrToStructure (), aby przekształcić IntPtr do użytecznej instancji interfejsu ID3D12Debug, ale to nie zadziała. Pamiętam, że czytałem o interfejsie ID3D12Debug będącym obiektem COM, ale czy nie potrzebujesz identyfikatora obiektu COM, aby móc go zaimportować? Nigdzie w dokumentacji nie znalazłem żadnego identyfikatora COM.

W każdym razie oto moja ostatnia próba wyciągnięcia czegoś z funkcji:

[DllImport("D3D12.dll")]
static extern int D3D12GetDebugInterface(IntPtr riid, IntPtr ppvDebug);

void func() {
    unsafe
    {
        IntPtr DebugControllerPtr = IntPtr.Zero;

        Type InterfaceType = typeof(ID3D12Debug);
        Guid ID = InterfaceType.GUID;
        IntPtr ptr = Marshal.AllocHGlobal(sizeof(Guid));
        Marshal.StructureToPtr(ID, ptr, false);

        D3D12GetDebugInterface(ptr, DebugControllerPtr);
        Marshal.FreeHGlobal(ptr);
        ID3D12Debug DebugController = null;
        Marshal.PtrToStructure(DebugControllerPtr, DebugController);
        DebugController.EnableDebugLayer();
    }
}

Jeśli chcesz zobaczyć mój interfejs ID3D12Debug:

interface ID3D12Debug
{
    void EnableDebugLayer();
}

Jak powiedziałem, myślę, że Direct3D korzysta z COM, którego tu zupełnie mi brakuje, więc może dlatego to nie działa.

Odpowiedzi

1 SimonMourier Sep 16 2020 at 20:41

Zwykle istnieje wiele sposobów zadeklarowania kodu międzyoperacyjnego. Oto taki, który powinien działać:

public static void Main()
{
    D3D12GetDebugInterface(typeof(ID3D12Debug).GUID, out var obj);
    var debug = (ID3D12Debug)obj;
    debug.EnableDebugLayer(); // for example
}

[DllImport("D3D12")]
public static extern int D3D12GetDebugInterface([MarshalAs(UnmanagedType.LPStruct)] Guid riid, [MarshalAs(UnmanagedType.IUnknown)] out object ppvDebug);

[Guid("344488b7-6846-474b-b989-f027448245e0"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ID3D12Debug
{
    [PreserveSig]
    void EnableDebugLayer();
}
  • W przypadku interfejsów COM należy dodać atrybuty Guid i InterfaceType interfejsu.
  • Guid można łatwo przekazać przez odniesienie za pomocą UnmanagedType.LPStruct
  • Nie potrzebujesz tutaj niebezpiecznego kodu.
  • Powinieneś sprawdzić błędy (cofnięte w moim kodzie)
  • Jeśli potrzebujesz definicji interfejsu .NET z DirectX, możesz użyć tego projektu open source tutaj: https://github.com/smourier/DirectN, na przykład: https://github.com/smourier/DirectN/blob/master/DirectN/DirectN/Generated/ID3D12Debug.cs