Home > Enterprise >  How to use Direct3D11CaptureFramePool in NET 5 / 6
How to use Direct3D11CaptureFramePool in NET 5 / 6

Time:04-07

Alternative title: WinRT support for IDirect3DDevice

I've an application that uses the "Direct3D11CaptureFramePool" class to capture the content of an application window as shown here (link)

I would like to port this example to NET 6.0

How to port WinRT code is described here link This worked as expected. But it was not possible for the IDirect3DDevice required by the CreateFreeThreaded method

How can i port this code to NET 6.0

    uint hr = CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.NativePointer, out IntPtr pUnknown);
    if (hr == 0)
    {
        device = Marshal.GetObjectForIUnknown(pUnknown) as IDirect3DDevice;
        Marshal.Release(pUnknown);
    }

There is no FromAbi method for IDrect3DDEvice as described here

Edit:

I have the Interface Type, I have a pointer to a IUnknown object, but i cannot get an instance because the Code to get an object for a IUnknown pointer has changed. There is no Windows.Graphics.DirectX.Direct3D11.IDirect3DDevice.FromAbi(pUnknown)

Edit 2:

I've created a sample repo to reproduce the problem: https://github.com/Amberg/GraphicsCaptureItemNet6Problem

This code works with NET 4.8 but not with NET 6. I belive because the call Marshal.GetObjectForIUnknown(pUnknown) should be replaced with IDirect3DDevice.FromAbi(pUnknown) but there is no such method

internal class Program
{

[DllImport(
        "d3d11.dll",
        EntryPoint = "CreateDirect3D11DeviceFromDXGIDevice",
        SetLastError = true,
        CharSet = CharSet.Unicode,
        ExactSpelling = true,
        CallingConvention = CallingConvention.StdCall
        )]
static extern UInt32 CreateDirect3D11DeviceFromDXGIDevice(IntPtr dxgiDevice, out IntPtr graphicsDevice);

static void Main(string[] args)
{

    using var sharpDxDevice = new SharpDX.Direct3D11.Device(SharpDX.Direct3D.DriverType.Hardware, SharpDX.Direct3D11.DeviceCreationFlags.BgraSupport);
    IDirect3DDevice direct3dDevice = CreateDirect3DDeviceFromSharpDXDevice(sharpDxDevice);

    // this will throw internal cast exception 
    using var framePool = Direct3D11CaptureFramePool.CreateFreeThreaded(
                        direct3dDevice,
                        DirectXPixelFormat.B8G8R8A8UIntNormalized,
                        2,
                        new SizeInt32(64, 64));

}

private static IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(SharpDX.Direct3D11.Device sharpDxDevice)
{
    IDirect3DDevice device = null;
    using (var dxgiDevice = sharpDxDevice.QueryInterface<SharpDX.DXGI.Device3>())
    {
        uint hr = CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.NativePointer, out IntPtr pUnknown);
        if (hr == 0)
        {
            // with NET 6 there should be something like 
            // IDirect3DDevice.FromAbi(pUnknown)
            // see here https://github.com/microsoft/CsWinRT/blob/master/docs/interop.md#create-rcw
            device = Marshal.GetObjectForIUnknown(pUnknown) as IDirect3DDevice;
            Marshal.Release(pUnknown);
        }
    }
    return device;
}
}

CodePudding user response:

With .NET 6 and CsWinRT, you can write your CreateDirect3DDeviceFromSharpDXDevice function like this:

private static IDirect3DDevice CreateDirect3DDeviceFromSharpDXDevice(SharpDX.Direct3D11.Device sharpDxDevice)
{
    if (CreateDirect3D11DeviceFromDXGIDevice(sharpDxDevice.NativePointer, out var punk) != 0)
        return null;

    return WinRT.MarshalInterface<IDirect3DDevice>.FromAbi(punk);
}
  • Related