Direct2D 和 Direct3D 互操作性的方法
ways for Direct2D and Direct3D Interoperability
我想制作一个 Direct2D GUI,它将 运行 在 DLL 上,并将使用我注入其中的应用程序的 Direct3D 呈现。
我知道我可以简单地使用 ID2D1Factory::CreateDxgiSurfaceRenderTarget
来制作 DXGI 表面并将其用作 d2d 渲染目标,但这需要在 Direct3D 设备上启用标志 D3D11_CREATE_DEVICE_BGRA_SUPPORT
。
问题是应用程序在没有启用此标志的情况下创建其设备,因此,ID2D1Factory::CreateDxgiSurfaceRenderTarget
失败。
我正在尝试寻找其他方法来绘制应用程序 window(在 window 的渲染目标外部或内部),如果 window 已满-屏幕。
到目前为止我尝试了这些替代方案:
使用 ID2D1Factory::CreateDCRenderTarget
创建 d2d 渲染目标。这有效,但我渲染的部分是 blinking/flashing(在循环中显示和隐藏非常快)。我在ID2D1RenderTarget::BeginDraw
之前也调用了ID2D1DCRenderTarget::BindDC
,但它只是闪烁但少了一点,所以我仍然有同样的问题。
创建一个新的 window,它将始终位于其他 window 的顶部,并使用 d2d 在那里呈现,但是,如果应用程序进入全屏,则此 window 未显示在屏幕上。
创建第二个启用 D3D11_CREATE_DEVICE_BGRA_SUPPORT
标志的 D3D 设备并在 window 的设备和我自己的设备之间共享一个 ID3D11Texture2D
资源,但我没有能够让它工作......关于如何做到这一点的例子并不多。我的想法是创建第二台设备,在该设备上使用 d2d 进行绘制,然后同步这两个 D3D 设备——我遵循了 this example(使用 direct11)。
创建一个D2D设备,将d2d设备的数据共享给d3d设备;但是,当我调用 ID2D1Factory1::CreateDevice
来创建设备时,它失败了,因为 D3D 设备是在没有启用 D3D11_CREATE_DEVICE_BGRA_SUPPORT
标志的情况下创建的。我从 this example.
开始
我听说过硬件覆盖,但它只适用于某些显卡,我想我会遇到问题 https://docs.microsoft.com/el-gr/windows/win32/medfound/hardware-overlay-support。
我目前正处于死胡同;我不知道该怎么办。有没有人有任何想法可以帮助我?
也许有什么方法可以在 window 全屏时在屏幕上绘图并工作?
#3 是正确的。这里有一些提示。
不要使用键控互斥体。不要使用 NT 句柄。您唯一需要的标志是 D3D11_RESOURCE_MISC_SHARED
.
要跨设备正确同步对共享纹理的访问,请使用查询。具体来说,您需要 D3D11_QUERY_EVENT
类型的查询。工作流程应如下所示。
在一台设备上创建共享纹理,在另一台设备上打开。它的创建位置和导入位置无关紧要。不要忘记 D3D11_BIND_RENDER_TARGET
标志。同时创建一个查询。
使用共享纹理的 CreateDxgiSurfaceRenderTarget 创建 D2D 设备,使用 D2D and/or DirectWrite 将叠加渲染到共享纹理中。
在带有用于 D2D 渲染的 BGRA 标志的直接 D3D 设备上下文中,调用 ID3D11DeviceContext.End
一次,传递查询。然后等待ID3D11DeviceContext.GetData
到returnS_OK。如果您关心 electricity/thermals 使用 Sleep(1)
,或者如果您优先考虑延迟,请忙于等待 _mm_pause()
指令。
一旦 ID3D11DeviceContext.GetData
return 为该查询编辑了 S_OK,GPU 就完成了 2D 场景的渲染。您现在可以在另一台设备上使用该纹理合成 3D 场景。
将 2D 内容组合到渲染目标中的方式取决于您想如何绘制 2D 内容。
如果那是一个小的不透明四边形,您可能 CopySubresourceRegion
进入渲染目标纹理。
或者,如果您的 2D 内容具有透明背景,您需要一个顶点 + 像素着色器来渲染一个四边形(4 个顶点)纹理与您的共享纹理。顺便说一句,你不一定需要一个 vertex/index 缓冲区,没有一个 well-known trick 也可以。不要忘记混合状态(你可能想要 alpha 混合),depth/stencil 状态(你可能想在渲染四边形时禁用深度测试),还有共享纹理的 D3D11_BIND_SHADER_RESOURCE
标志。
P.S。还有另一种方法。确保您的代码在该进程创建其 Direct3D 设备之前在该进程中运行。然后使用minhook之类的东西拦截对D3D11.dll::D3D11CreateDeviceAndSwapChain的调用,在拦截的函数中设置你需要的BGRA位然后调用原始函数。不太可靠,因为有多种方法可以创建 D3D 设备,但更容易实现,工作速度更快,使用的内存更少。
我想制作一个 Direct2D GUI,它将 运行 在 DLL 上,并将使用我注入其中的应用程序的 Direct3D 呈现。
我知道我可以简单地使用 ID2D1Factory::CreateDxgiSurfaceRenderTarget
来制作 DXGI 表面并将其用作 d2d 渲染目标,但这需要在 Direct3D 设备上启用标志 D3D11_CREATE_DEVICE_BGRA_SUPPORT
。
问题是应用程序在没有启用此标志的情况下创建其设备,因此,ID2D1Factory::CreateDxgiSurfaceRenderTarget
失败。
我正在尝试寻找其他方法来绘制应用程序 window(在 window 的渲染目标外部或内部),如果 window 已满-屏幕。
到目前为止我尝试了这些替代方案:
使用
ID2D1Factory::CreateDCRenderTarget
创建 d2d 渲染目标。这有效,但我渲染的部分是 blinking/flashing(在循环中显示和隐藏非常快)。我在ID2D1RenderTarget::BeginDraw
之前也调用了ID2D1DCRenderTarget::BindDC
,但它只是闪烁但少了一点,所以我仍然有同样的问题。创建一个新的 window,它将始终位于其他 window 的顶部,并使用 d2d 在那里呈现,但是,如果应用程序进入全屏,则此 window 未显示在屏幕上。
创建第二个启用
D3D11_CREATE_DEVICE_BGRA_SUPPORT
标志的 D3D 设备并在 window 的设备和我自己的设备之间共享一个ID3D11Texture2D
资源,但我没有能够让它工作......关于如何做到这一点的例子并不多。我的想法是创建第二台设备,在该设备上使用 d2d 进行绘制,然后同步这两个 D3D 设备——我遵循了 this example(使用 direct11)。创建一个D2D设备,将d2d设备的数据共享给d3d设备;但是,当我调用
开始ID2D1Factory1::CreateDevice
来创建设备时,它失败了,因为 D3D 设备是在没有启用D3D11_CREATE_DEVICE_BGRA_SUPPORT
标志的情况下创建的。我从 this example.
我听说过硬件覆盖,但它只适用于某些显卡,我想我会遇到问题 https://docs.microsoft.com/el-gr/windows/win32/medfound/hardware-overlay-support。
我目前正处于死胡同;我不知道该怎么办。有没有人有任何想法可以帮助我?
也许有什么方法可以在 window 全屏时在屏幕上绘图并工作?
#3 是正确的。这里有一些提示。
不要使用键控互斥体。不要使用 NT 句柄。您唯一需要的标志是 D3D11_RESOURCE_MISC_SHARED
.
要跨设备正确同步对共享纹理的访问,请使用查询。具体来说,您需要 D3D11_QUERY_EVENT
类型的查询。工作流程应如下所示。
在一台设备上创建共享纹理,在另一台设备上打开。它的创建位置和导入位置无关紧要。不要忘记
D3D11_BIND_RENDER_TARGET
标志。同时创建一个查询。使用共享纹理的 CreateDxgiSurfaceRenderTarget 创建 D2D 设备,使用 D2D and/or DirectWrite 将叠加渲染到共享纹理中。
在带有用于 D2D 渲染的 BGRA 标志的直接 D3D 设备上下文中,调用
ID3D11DeviceContext.End
一次,传递查询。然后等待ID3D11DeviceContext.GetData
到returnS_OK。如果您关心 electricity/thermals 使用Sleep(1)
,或者如果您优先考虑延迟,请忙于等待_mm_pause()
指令。一旦
ID3D11DeviceContext.GetData
return 为该查询编辑了 S_OK,GPU 就完成了 2D 场景的渲染。您现在可以在另一台设备上使用该纹理合成 3D 场景。
将 2D 内容组合到渲染目标中的方式取决于您想如何绘制 2D 内容。
如果那是一个小的不透明四边形,您可能 CopySubresourceRegion
进入渲染目标纹理。
或者,如果您的 2D 内容具有透明背景,您需要一个顶点 + 像素着色器来渲染一个四边形(4 个顶点)纹理与您的共享纹理。顺便说一句,你不一定需要一个 vertex/index 缓冲区,没有一个 well-known trick 也可以。不要忘记混合状态(你可能想要 alpha 混合),depth/stencil 状态(你可能想在渲染四边形时禁用深度测试),还有共享纹理的 D3D11_BIND_SHADER_RESOURCE
标志。
P.S。还有另一种方法。确保您的代码在该进程创建其 Direct3D 设备之前在该进程中运行。然后使用minhook之类的东西拦截对D3D11.dll::D3D11CreateDeviceAndSwapChain的调用,在拦截的函数中设置你需要的BGRA位然后调用原始函数。不太可靠,因为有多种方法可以创建 D3D 设备,但更容易实现,工作速度更快,使用的内存更少。