通过 RDP 使用 WPF 的 Direct2d
Direct2d with WPF over RDP
我正在开发一个 C# 应用程序,它使用 SharpDx 通过 Direct2d 渲染地图。此地图与 WPF 主机上的 D3DImage 一起显示。在本地计算机上一切正常,但是当我尝试通过远程桌面连接时,D3DImage 丢失了它的后备缓冲区,渲染的图像无法使用 WPF 显示。
我尝试在绑定后备缓冲区时启用软件回退。结果是应用程序设法渲染了一张图像,然后再次丢失了后备缓冲区。
我还尝试使用 gpedit 在远程桌面连接上启用硬件加速,但没有任何改变。
public void SetBackBuffer(D3D11.Texture2D texture)
{
using (var device = CreateDevice(NativeMethods.GetDesktopWindow()))
{
using (var texture9 = GetSharedSurface(device, texture))
{
this.surface = texture9.GetSurfaceLevel(0);
}
}
this.Lock();
this.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface.NativePointer, true);
this.Unlock();
}
private static D3D9.Texture GetSharedSurface(D3D9.Device device, D3D11.Texture2D texture)
{
using (var surface = texture.QueryInterface<DXGI.Resource>())
{
IntPtr handle = surface.SharedHandle;
return new D3D9.Texture(
device,
texture.Description.Width,
texture.Description.Height,
1,
D3D9.Usage.RenderTarget,
D3D9.Format.A8R8G8B8, // D3DFMT_A8R8G8B8
D3D9.Pool.Default, // D3DPOOL_DEFAULT
ref handle);
}
}
private static D3D9.DeviceEx CreateDevice(IntPtr handle)
{
using (var d3D9Ex = new D3D9.Direct3DEx())
{
var present = new D3D9.PresentParameters
{
Windowed = true,
SwapEffect = D3D9.SwapEffect.Discard,
DeviceWindowHandle = handle,
PresentationInterval = D3D9.PresentInterval.Immediate,
};
const D3D9.CreateFlags CreateFlags = D3D9.CreateFlags.HardwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve;
return new D3D9.DeviceEx(
d3D9Ex,
0, // D3DADAPTER_DEFAULT
D3D9.DeviceType.Hardware, // D3DDEVTYPE_HAL
handle,
CreateFlags,
present);
}
}
编辑
当我使用 HKEY_CURRENT_USER/SOFTWARE/Microsoft/Avolon.Graphics/DisableHWAcceleration 禁用硬件加速时,我在没有 RDP 的本地计算机上遇到了同样的问题。
编辑2
我尝试使用 Direct11 创建参考或变形设备。但经过一番研究后发现,这两种软件设备都不支持我用来创建 WPF 图像的 SharedSurfaces。
所以我找到了解决问题的方法:
首先,当您将 BackBuffer 绑定到 D3DImage 时,您必须启用软件回退。我的问题是,在我收到 IsFrontBufferAvailableChanged 事件的一帧后,IsFrontBufferAvailable 变为 false,我停止了渲染。但是在软件渲染中你可以忽略这些东西。
这是一个 github 问题,它帮助我修复了它:
https://github.com/Sascha-L/WPF-MediaKit/issues/3
我正在开发一个 C# 应用程序,它使用 SharpDx 通过 Direct2d 渲染地图。此地图与 WPF 主机上的 D3DImage 一起显示。在本地计算机上一切正常,但是当我尝试通过远程桌面连接时,D3DImage 丢失了它的后备缓冲区,渲染的图像无法使用 WPF 显示。
我尝试在绑定后备缓冲区时启用软件回退。结果是应用程序设法渲染了一张图像,然后再次丢失了后备缓冲区。 我还尝试使用 gpedit 在远程桌面连接上启用硬件加速,但没有任何改变。
public void SetBackBuffer(D3D11.Texture2D texture)
{
using (var device = CreateDevice(NativeMethods.GetDesktopWindow()))
{
using (var texture9 = GetSharedSurface(device, texture))
{
this.surface = texture9.GetSurfaceLevel(0);
}
}
this.Lock();
this.SetBackBuffer(D3DResourceType.IDirect3DSurface9, this.surface.NativePointer, true);
this.Unlock();
}
private static D3D9.Texture GetSharedSurface(D3D9.Device device, D3D11.Texture2D texture)
{
using (var surface = texture.QueryInterface<DXGI.Resource>())
{
IntPtr handle = surface.SharedHandle;
return new D3D9.Texture(
device,
texture.Description.Width,
texture.Description.Height,
1,
D3D9.Usage.RenderTarget,
D3D9.Format.A8R8G8B8, // D3DFMT_A8R8G8B8
D3D9.Pool.Default, // D3DPOOL_DEFAULT
ref handle);
}
}
private static D3D9.DeviceEx CreateDevice(IntPtr handle)
{
using (var d3D9Ex = new D3D9.Direct3DEx())
{
var present = new D3D9.PresentParameters
{
Windowed = true,
SwapEffect = D3D9.SwapEffect.Discard,
DeviceWindowHandle = handle,
PresentationInterval = D3D9.PresentInterval.Immediate,
};
const D3D9.CreateFlags CreateFlags = D3D9.CreateFlags.HardwareVertexProcessing | D3D9.CreateFlags.Multithreaded | D3D9.CreateFlags.FpuPreserve;
return new D3D9.DeviceEx(
d3D9Ex,
0, // D3DADAPTER_DEFAULT
D3D9.DeviceType.Hardware, // D3DDEVTYPE_HAL
handle,
CreateFlags,
present);
}
}
编辑 当我使用 HKEY_CURRENT_USER/SOFTWARE/Microsoft/Avolon.Graphics/DisableHWAcceleration 禁用硬件加速时,我在没有 RDP 的本地计算机上遇到了同样的问题。
编辑2 我尝试使用 Direct11 创建参考或变形设备。但经过一番研究后发现,这两种软件设备都不支持我用来创建 WPF 图像的 SharedSurfaces。
所以我找到了解决问题的方法:
首先,当您将 BackBuffer 绑定到 D3DImage 时,您必须启用软件回退。我的问题是,在我收到 IsFrontBufferAvailableChanged 事件的一帧后,IsFrontBufferAvailable 变为 false,我停止了渲染。但是在软件渲染中你可以忽略这些东西。
这是一个 github 问题,它帮助我修复了它: https://github.com/Sascha-L/WPF-MediaKit/issues/3