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

2023-10-22 10:58:38 浏览数 (1)

如果你得到了一个来自于其他进程或者其他模块的 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 设备之间共享资源。需要设置 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 组件引用之后,可以在内存中映射位图用于调试,可以参见:

  • 将 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]) 。

0 人点赞