DirectX 到 OpenGL 热插拔,在 Win32 上不显示 window
DirectX to OpenGL hot-swap, doesn't display on Win32 window
在我的引擎开发过程中,我正在尝试实现一项功能,该功能支持 OpenGL 和 DirectX 之间的热交换。目前在Win32平台上测试,遇到以下问题:
我实现了两种渲染器(OpenGL 3.0 和 Direct3D11),两者都可以单独使用。交换机制如下:
销毁当前的渲染上下文,并建立新的渲染上下文。例如:释放所有 DirectX 对象,然后通过 WGL 创建 OpenGL 上下文。我正在尝试仅使用一个 window (HWND).
来实现这一点
可以从 OpenGL 3.0 切换到 DirectX11。 (破坏OpenGL后,DirectX渲染正常)
销毁 OpenGL 然后重新创建 OpenGL,有效。与 DirectX 相同。
当我尝试从 DirectX 切换到 OpenGL 时,window 将停止显示新绘制的内容,只显示最后绘制的 DirectX 帧。
为了构建 OpenGL 上下文,我正在使用 WGL。 window 的 class 是使用 CS_OWNDC
样式创建的。我正在使用 SwapBuffers
翻转 window 缓冲区。在设置上下文之前,我将 SetPixelFormat
与之前 ChoosePixelFormat
中的 returned 值一起使用。创建的上下文是 3.0 版,通过 wglCreateContextAttribsARB
.
确保
附加信息:
释放所有 DirectX 引用,这是通过调用 ReportLiveDeviceObjects
并检查 ID3D11Device1::Release
(0) 的 return 值来检查的。 ID3D11DeviceContext1::ClearState
和 Flush
被调用以确保对象销毁。
None 的 OpenGL 方法通过 glGetError
报告错误,每次调用后都会检查。这对所有 OS 和 WGL 调用都是相同的。
OpenGL 渲染调用按预期执行,例如:
- 150 fps 的 OpenGL 渲染
- 切换到 DirectX,以 60 fps (VSYNC) 渲染
- 切换回 OpenGL,再次以 150 fps(不更高)渲染
在其他情况下,OpenGL 渲染速度超过 150 fps,因此渲染调用执行正常。
我的猜测是缓冲区的翻转以某种方式不起作用,但是 SwapBuffers
returns TRUE
无论如何。
我尝试在使用 DirectX 之前和之后使用 SaveDC
和 RestoreDC
,这导致了现在的解决方案。
使用 wglSwapLayerBuffers
而不是 SwapBuffers
没有变化。
我能否以某种方式将 HWND 或 HDC 恢复到原始状态,或者你们知道为什么会发生这种情况吗?
我想我很快就发布了我的问题,但是,这就是我解决问题的方法。
我仔细研究了 DirectX 的文档和函数 CreateSwapChainForHwnd
,我发现了以下内容:
Because you can associate only one flip presentation model swap chain at a time with an HWND, the Microsoft Direct3D 11 policy of deferring the destruction of objects can cause problems if you attempt to destroy a flip presentation model swap chain and replace it with another swap chain.
我在我的交换链描述符中使用 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
,这可能意味着 DirectX 为 window 设置了翻转交换链,但是当我尝试将它与 OpenGL 一起使用时,它会以某种方式无法交换缓冲区。
解决方法是不使用 FLIP
模式创建交换链:
DXGI_SWAP_CHAIN_DESC1 scd;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Scaling = DXGI_SCALING_ASPECT_RATIO_STRETCH;
您必须将 Scaling
设置为 DXGI_SCALING_NONE
以外的值,否则创建将失败。
有趣的是,DirectX 仍然没有正确破坏 window 上的翻转模型,尽管我按照文档中的建议做了所有操作(ClearState
和 Flush
电话)。
CreateSwapChainForHwnd
see Remarks
编辑:一段时间后我发现了 this 个问题。如果有人仍然知道如何恢复使用 GDI 而不是 DWM 后备缓冲区,我们将不胜感激。
在我的引擎开发过程中,我正在尝试实现一项功能,该功能支持 OpenGL 和 DirectX 之间的热交换。目前在Win32平台上测试,遇到以下问题:
我实现了两种渲染器(OpenGL 3.0 和 Direct3D11),两者都可以单独使用。交换机制如下:
销毁当前的渲染上下文,并建立新的渲染上下文。例如:释放所有 DirectX 对象,然后通过 WGL 创建 OpenGL 上下文。我正在尝试仅使用一个 window (HWND).
来实现这一点可以从 OpenGL 3.0 切换到 DirectX11。 (破坏OpenGL后,DirectX渲染正常)
销毁 OpenGL 然后重新创建 OpenGL,有效。与 DirectX 相同。
当我尝试从 DirectX 切换到 OpenGL 时,window 将停止显示新绘制的内容,只显示最后绘制的 DirectX 帧。
为了构建 OpenGL 上下文,我正在使用 WGL。 window 的 class 是使用 CS_OWNDC
样式创建的。我正在使用 SwapBuffers
翻转 window 缓冲区。在设置上下文之前,我将 SetPixelFormat
与之前 ChoosePixelFormat
中的 returned 值一起使用。创建的上下文是 3.0 版,通过 wglCreateContextAttribsARB
.
附加信息:
释放所有 DirectX 引用,这是通过调用 ReportLiveDeviceObjects
并检查 ID3D11Device1::Release
(0) 的 return 值来检查的。 ID3D11DeviceContext1::ClearState
和 Flush
被调用以确保对象销毁。
None 的 OpenGL 方法通过 glGetError
报告错误,每次调用后都会检查。这对所有 OS 和 WGL 调用都是相同的。
OpenGL 渲染调用按预期执行,例如:
- 150 fps 的 OpenGL 渲染
- 切换到 DirectX,以 60 fps (VSYNC) 渲染
- 切换回 OpenGL,再次以 150 fps(不更高)渲染
在其他情况下,OpenGL 渲染速度超过 150 fps,因此渲染调用执行正常。
我的猜测是缓冲区的翻转以某种方式不起作用,但是 SwapBuffers
returns TRUE
无论如何。
我尝试在使用 DirectX 之前和之后使用 SaveDC
和 RestoreDC
,这导致了现在的解决方案。
使用 wglSwapLayerBuffers
而不是 SwapBuffers
没有变化。
我能否以某种方式将 HWND 或 HDC 恢复到原始状态,或者你们知道为什么会发生这种情况吗?
我想我很快就发布了我的问题,但是,这就是我解决问题的方法。
我仔细研究了 DirectX 的文档和函数 CreateSwapChainForHwnd
,我发现了以下内容:
Because you can associate only one flip presentation model swap chain at a time with an HWND, the Microsoft Direct3D 11 policy of deferring the destruction of objects can cause problems if you attempt to destroy a flip presentation model swap chain and replace it with another swap chain.
我在我的交换链描述符中使用 DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL
,这可能意味着 DirectX 为 window 设置了翻转交换链,但是当我尝试将它与 OpenGL 一起使用时,它会以某种方式无法交换缓冲区。
解决方法是不使用 FLIP
模式创建交换链:
DXGI_SWAP_CHAIN_DESC1 scd;
scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scd.Scaling = DXGI_SCALING_ASPECT_RATIO_STRETCH;
您必须将 Scaling
设置为 DXGI_SCALING_NONE
以外的值,否则创建将失败。
有趣的是,DirectX 仍然没有正确破坏 window 上的翻转模型,尽管我按照文档中的建议做了所有操作(ClearState
和 Flush
电话)。
CreateSwapChainForHwnd
see Remarks
编辑:一段时间后我发现了 this 个问题。如果有人仍然知道如何恢复使用 GDI 而不是 DWM 后备缓冲区,我们将不胜感激。