如果你得到了一个来自于其他进程或者其他模块的 Direct3D11 的共享资源,即 SharedHandle 句柄,那么可以使用本文提到的方法将其转换成 Direct3D11 的设备和纹理,这样你可以进行后续的其他处理。
SharpDX
本文的代码会使用到 SharpDX 库,因此,你需要在你的项目当中安装这些 NuGet 包:
1 2 3 4 5 6 7 8 9 10 | <!-- 基础,必装 --><br><PackageReference Include="SharpDX" Version="4.2.0" /><br><PackageReference Include="SharpDX.D3DCompiler" Version="4.2.0" /><br><PackageReference Include="SharpDX.DXGI" Version="4.2.0" /><br><PackageReference Include="SharpDX.Mathematics" Version="4.2.0" /><br><PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" /><br><br><!-- 其他,可选 --><br><PackageReference Include="SharpDX.Direct2D1" Version="4.2.0" /><br><PackageReference Include="SharpDX.Direct3D9" Version="4.2.0" /> |
---|
SharedHandle
Direct3D 支持在不同的 Direct3D 设备之间共享资源。需要设置 ResourceOptionFlags
为 Shared
的纹理才可以支持共享,当然这不是本文要说的重点。
本文要说的是,如果你拿到了一个来自于其他模块的共享资源句柄的时候,你可以如何使用它。
你的使用可能类似于这样:
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 组件引用之后,可以在内存中映射位图用于调试,可以参见:
- 将 Direct3D11 在 GPU 中的纹理(Texture2D)导出到内存或导出成图片文件
参考资料
- c - Direct3D11: Sharing a texture between devices: black texture - Stack Overflow
- ID3D11Device::OpenSharedResource (d3d11.h) - Microsoft Docs
- IDXGIResource interface (Windows)(https://msdn.microsoft.com/en-us/windows/hardware/bb174560(v=vs.110))
- IDXGIResource (dxgi.h) - Microsoft Docs
- IUnknown::QueryInterface(Q,) - Microsoft Docs(https://docs.microsoft.com/en-us/windows/win32/api/unknwn/nf-unknwn-iunknown-queryinterface(q_))
本文会经常更新,请阅读原文: https://blog.walterlv.com/post/direct3d11-open-shared-resource.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。