Files
ytLlive/Services/Direct3D11Helper.cs
T

84 lines
3.3 KiB
C#

using System;
using System.Runtime.InteropServices;
using Windows.Graphics.DirectX.Direct3D11;
using WinRT;
namespace ytLive.Services;
/// <summary>
/// Bridges a native D3D11 device into the WinRT <see cref="IDirect3DDevice"/>
/// the capture API needs. CsWinRT doesn't project the Direct3D11Helper static,
/// so this creates the device with D3D11CreateDevice and converts it via the
/// WinRT interop export <c>CreateDirect3D11DeviceFromDXGIDevice</c> (d3d11.dll).
///
/// This deliberately does NOT use the older QI-for-IDirect3DDxgiInterfaceAccess
/// trick: the raw D3D11 device stopped exposing that interface on newer Windows
/// (verified E_NOINTERFACE on build 26200, hardware and WARP alike), while
/// CreateDirect3D11DeviceFromDXGIDevice keeps working. One shared device per
/// process.
/// </summary>
internal static class Direct3D11Helper
{
private const uint D3D11CreateDeviceBgraSupport = 0x20;
private const uint D3D11SdkVersion = 7;
private const int DriverTypeHardware = 1;
// IDirect3DDxgiInterfaceAccess (the legacy bridge) is only exposed on an
// 11.1 device AND requires the 11.1 runtime to be in the requested set —
// with pFeatureLevels = NULL D3D11CreateDevice never creates 11.1, so the
// array must be explicit (11.1 first, then descending).
private static readonly int[] FeatureLevels = { 0xB100, 0xB000, 0xA100, 0xA000, 0x9300, 0x9200, 0x9100 };
private static IDirect3DDevice? _sharedDevice;
private static readonly object Gate = new();
public static IDirect3DDevice CreateDevice()
{
if (_sharedDevice != null) return _sharedDevice;
lock (Gate)
{
return _sharedDevice ??= CreateDeviceCore();
}
}
private static IDirect3DDevice CreateDeviceCore()
{
var hr = D3D11CreateDevice(IntPtr.Zero, DriverTypeHardware, IntPtr.Zero, D3D11CreateDeviceBgraSupport,
FeatureLevels, (uint)FeatureLevels.Length, D3D11SdkVersion, out var devicePtr, out _, out var contextPtr);
if (hr != 0)
throw Marshal.GetExceptionForHR(hr)!;
try
{
var dxgiGuid = new Guid("54EC77FA-1377-44E6-8C32-88FD5F44C84C");
var qiHr = Marshal.QueryInterface(devicePtr, ref dxgiGuid, out var dxgiDevice);
if (qiHr != 0)
throw Marshal.GetExceptionForHR(qiHr)!;
try
{
hr = CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice, out var winrtDevice);
if (hr != 0)
throw Marshal.GetExceptionForHR(hr)!;
return MarshalInterface<IDirect3DDevice>.FromAbi(winrtDevice);
}
finally
{
Marshal.Release(dxgiDevice);
}
}
finally
{
Marshal.Release(devicePtr);
Marshal.Release(contextPtr);
}
}
[DllImport("d3d11.dll")]
private static extern int D3D11CreateDevice(IntPtr pAdapter, int driverType, IntPtr software,
uint flags, int[]? featureLevels, uint featureLevelsCount, uint sdkVersion,
out IntPtr device, out int featureLevel, out IntPtr immediateContext);
[DllImport("d3d11.dll", ExactSpelling = true)]
private static extern int CreateDirect3D11DeviceFromDXGIDevice(IntPtr dxgiDevice, out IntPtr graphicsDevice);
}