Como usar a API D3D12GetDebugInterface de c #?

Sep 16 2020

Atualmente, estou tentando usar o Direct3D de c # e comecei usando a API D3D12GetDebugInterface. A sintaxe C ++ da função é a seguinte (copiada da documentação da Microsoft):

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

Estou tendo problemas para importar a função para C #. Achei que talvez riid devesse ser um ponteiro para uma estrutura Guid, e estou apenas usando um IntPtr para ** ppvDebug. Como ** ppvDebug é um ponteiro para um ponteiro para uma interface ID3D12Debug, tentei reimplementar a interface ID3D12Debug no código C # e usar Marshal.PtrToStructure () para resolver o IntPtr para uma instância de interface ID3D12Debug utilizável, mas isso não funcionou. Lembro-me de ter lido sobre a interface ID3D12Debug ser um objeto COM, mas você não precisa de um ID para um objeto COM para poder importá-lo? Não encontrei nenhum tipo de ID COM em qualquer lugar da documentação.

De qualquer forma, aqui está minha última tentativa de tirar algo da função:

[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();
    }
}

Caso você queira ver minha interface ID3D12Debug:

interface ID3D12Debug
{
    void EnableDebugLayer();
}

Como eu disse, acho que o Direct3D usa COM, do qual estou totalmente ausente aqui, então talvez seja por isso que ele não funciona.

Respostas

1 SimonMourier Sep 16 2020 at 20:41

Normalmente, há muitas maneiras de declarar o código de interoperabilidade. Aqui está um que deve funcionar:

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();
}
  • Você deve adicionar atributos de interface Guid e InterfaceType para interfaces COM.
  • O Guid pode ser passado facilmente por referência usando UnmanagedType.LPStruct
  • Você não precisa de código inseguro aqui.
  • Você deve verificar se há erros (desfeito em meu código)
  • Se precisar de definições de interface .NET com DirectX, você pode usar este projeto de código aberto aqui: https://github.com/smourier/DirectN, por exemplo: https://github.com/smourier/DirectN/blob/master/DirectN/DirectN/Generated/ID3D12Debug.cs