取消

使用 Direct3D11 的 OpenSharedResource 方法渲染来自其他进程/设备的共享资源(SharedHandle)

如果你得到了一个来自于其他进程或者其他模块的 Direct3D11 的共享资源,即 SharedHandle 句柄,那么可以使用本文提到的方法将其转换成 Direct3D11 的设备和纹理,这样你可以进行后续的其他处理。


SharpDX

本文的代码会使用到 SharpDX 库,因此,你需要在你的项目当中安装这些 NuGet 包:

1
2
3
4
5
6
7
8
9
10
<!-- 基础,必装 -->
<PackageReference Include="SharpDX" Version="4.2.0" />
<PackageReference Include="SharpDX.D3DCompiler" Version="4.2.0" />
<PackageReference Include="SharpDX.DXGI" Version="4.2.0" />
<PackageReference Include="SharpDX.Mathematics" Version="4.2.0" />
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />

<!-- 其他,可选 -->
<PackageReference Include="SharpDX.Direct2D1" Version="4.2.0" />
<PackageReference Include="SharpDX.Direct3D9" Version="4.2.0" />

SharedHandle

Direct3D 支持在不同的 Direct3D 设备之间共享资源。需要设置 ResourceOptionFlagsShared 的纹理才可以支持共享,当然这不是本文要说的重点。

本文要说的是,如果你拿到了一个来自于其他模块的共享资源句柄的时候,你可以如何使用它。

你的使用可能类似于这样:

1
2
3
4
public void OnAcceleratedPaint(IntPtr sharedHandle, Int32Rect dirtyRect)
{
    // 通过 sharedHandle 进行后续的处理。
}

OpenSharedResource

DirectX 中用来表示 Direct3D11 的设备类型是 ID3D11Device,它有一个 OpenSharedResource 方法可以用来打开来自于其他设备的共享资源。

对应到 SharpDX 中,用来表示 Direct3D11 的设备的类型是 SharpDX.Direct3D11.Device,其有一个 OpenSharedResource<T> 方法来打开来自于其他设备的共享资源。

我们必须要创建一个自己的 Direct3D11 设备,因为设备是不共享的,代码如下:

1
2
var device = new SharpDX.Direct3D11.Device(DriverType.Hardware, DeviceCreationFlags.BgraSupport);
var resource = device.OpenSharedResource<SharpDX.Direct3D11.Resource>(sharedHandle);

后续操作

在得到此共享资源之后,我们可以获得更多关于此资源的描述,以及有限地使用此资源的方法。

获取 Texture2D

可以通过 QueryInterface 获取某个资源相关的 COM 对象的引用。我们拿到的共享资源是 2D 纹理的话,我们可以使用 QueryInterface 获取 SharpDX.Direct3D11.Texture2D COM 对象的引用。

1
var texture = resource.QueryInterface<SharpDX.Direct3D11.Texture2D>();

获取 Texture2DDescription

可以从 Texture2D 的实例中获取到 Texture2DDescription,这是用来描述此 2D 纹理创建时的各种信息。

1
2
3
// 在 DirectX 的传统代码中,通常使用 desc 来作为 Texture2DDescription 实例命名的后缀。
// 不过 C# 代码通常不这么干,这是 C++ 代码的习惯。在这里这么写是为了在得到 C++ 搜索结果的时候可以与本文所述的 C# 代码对应起来。
var desc = texture.Description;

获取 Surface

或者,我们可以获取到 2D 图面,用于做渲染、绘制等操作。当然,是否能真正进行这些操作取决于 Texture2DDescription 中是否允许相关的操作。

1
var surface = texture2D.QueryInterface<SharpDX.DXGI.Surface>();

在获取到 SharpDX.DXGI.Surface 的 COM 组件引用之后,可以在内存中映射位图用于调试,可以参见:


参考资料

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/direct3d11-open-shared-resource.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])

登录 GitHub 账号进行评论