Search code examples
winapiopengldirectxhwndhotswap

DirectX to OpenGL hot-swap, doesn't display on Win32 window


During the developement of my engine, I'm trying to implement a feature, that enables hot-swapping between OpenGL and DirectX. Currently I'm testing on Win32 platform, and came across the following problem:

I implemented both renderer (OpenGL 3.0, and Direct3D11), both work fine alone. The swapping mechanism is the following:

Destroy the current rendering context, and build up the new one. For example: Release all DirectX objects, and then create OpenGL context, via WGL. I'm trying to implement this, using only one window (HWND).

Swapping from OpenGL 3.0 to DirectX11 works. (After destroying OpenGL, DirectX renders fine)

Destroying OpenGL and then recreating OpenGL again, works. Same with DirectX.

When I'm trying to swap from DirectX to OpenGL, the window will stop displaying the newly draw content, only the lastly drawn DirectX frame.

To construct the OpenGL context I'm using WGL. The class for the window was created with the CS_OWNDC style. I'm using SwapBuffers to flip the window buffers. Before setting up the context, I use SetPixelFormat with the previously returned value from ChoosePixelFormat. The created context is version 3.0, ensured via wglCreateContextAttribsARB.

Additional information:

All of the DirectX references are released, this was checked by calling ReportLiveDeviceObjects and checking the return value of ID3D11Device1::Release (0). ID3D11DeviceContext1::ClearState and Flush were called to ensure object destruction.

None of the OpenGL methods report error via glGetError, this is checked after every call. This is same for all OS, and WGL calls.

The OpenGL rendering calls are executing as expected, for example:

  1. OpenGL rendering with 150 fps
  2. Swap to DirectX, render with 60 fps (VSYNC)
  3. Swap back to OpenGL, rendering again with 150 fps (not more)

There are other scenarios where OpenGL renders with more than 150 fps, so the rendering calls are executing properly.

My guess is that the flipping of the buffers doesn't work somehow, however SwapBuffers returns TRUE anyway.

I tried using SaveDC and RestoreDC before and after using DirectX, this resulted in now solution.

Using wglSwapLayerBuffers instead of SwapBuffers gives no change.

Can I somehow restore the HWND, or HDC to the original state, or do you guys have any idea why this might happen?


Solution

  • Guess I posted my question to soon, but however, this is how I solved it.

    I dug around the documnentation for DirectX, and for the function CreateSwapChainForHwnd, I found the following:

    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.

    I was using DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL in my swap chain descriptor, and this could mean, that DirectX sets up a flip swap chain for the window, but when I try to use it with OpenGL, it will fail swapping buffers somehow.

    The solution for this, is to not use FLIP mode for creating the swap chain:

    DXGI_SWAP_CHAIN_DESC1 scd;
    scd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;          
    scd.Scaling = DXGI_SCALING_ASPECT_RATIO_STRETCH;
    

    You have to set the Scaling to something else than DXGI_SCALING_NONE, or the creation will fail.

    The interesting part is, that the DirectX still does not properly destroy the flip model on the window, altough I did everything it suggested in the documentation (ClearState and Flush calls).

    CreateSwapChainForHwnd see Remarks

    Edit: I found this question after some time. If anybody still has some idea, how to revert back to using GDI again instead of the DWM backbuffer, it is greatly appreciated.