Как использовать D3D12GetDebugInterface API из c #?

Sep 16 2020

В настоящее время я пытаюсь использовать Direct3D из C #, и я начал с использования API D3D12GetDebugInterface. Синтаксис функции C ++ следующий (скопирован из документации Microsoft):

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

У меня проблемы с импортом функции в C #. Я подумал, что, возможно, riid должен быть указателем на структуру Guid, а я просто использую IntPtr для ** ppvDebug. Поскольку ** ppvDebug - это указатель на указатель на интерфейс ID3D12Debug, я попытался повторно реализовать интерфейс ID3D12Debug в коде C # и использовать Marshal.PtrToStructure () для преобразования IntPtr в пригодный для использования экземпляр интерфейса ID3D12Debug, но это не сработало. Я помню, как читал о том, что интерфейс ID3D12Debug является COM-объектом, но разве вам не нужен идентификатор COM-объекта, чтобы вы могли его импортировать? Я нигде в документации не нашел COM ID.

В любом случае, вот моя последняя попытка получить что-то от функции:

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

Если вы хотите увидеть мой интерфейс ID3D12Debug:

interface ID3D12Debug
{
    void EnableDebugLayer();
}

Как я уже сказал, я думаю, что Direct3D использует COM, которого мне здесь совершенно не хватает, так что, возможно, поэтому он не работает.

Ответы

1 SimonMourier Sep 16 2020 at 20:41

Обычно есть много способов объявить код взаимодействия. Вот тот, который должен работать:

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();
}
  • Вы должны добавить атрибуты интерфейса Guid и InterfaceType для COM-интерфейсов.
  • Guid можно легко передать по ссылке, используя UnmanagedType.LPStruct
  • Здесь вам не нужен небезопасный код.
  • Вы должны проверить наличие ошибок (отменено в моем коде)
  • Если вам нужны определения интерфейса .NET с DirectX, вы можете использовать этот проект с открытым исходным кодом здесь: https://github.com/smourier/DirectN, Например: https://github.com/smourier/DirectN/blob/master/DirectN/DirectN/Generated/ID3D12Debug.cs