Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [Tutorial] How to Recreate Window without destroying the Context  (Read 2193 times)

0 Members and 1 Guest are viewing this topic.

Powereleven

  • Newbie
  • *
  • Posts: 36
    • View Profile
Hello, SFML Forums.

This post is for people who mix custom OpenGL code with SFML.

It's not new that frameworks (like SFML) don't expose low level functionality to be able to keep the same OpenGL context when creating a new window (https://stackoverflow.com/questions/12881049/recreate-window-without-destroying-the-context).

I'm writing this post to show how I managed to minimally adapt SFML's code to support this feature on Windows.

Before, I used to manually delete all my OpenGL resources, call window.create(), then create then back. This is cumbersome and slow, specially when a lot of gigabytes of data are already sitting in the GPU. OpenGL resources included VAO, VBO, FBO, UBO, Shaders, Textures, etc. Now, after recreating the window, I only have to update stuff that actually depend on the window size, like my FBO's GL_TEXTURE_RECTANGLE's with glTexImage2D. Everything is preserved.

We are going to change some things in sfml-window's project.

Firstly, add the directory src\SFML\Window\Win32 to the project's include path. Then, in src/SFML/Window/Window.cpp, add the header #include <SFML/Window/Win32/WglContext.hpp> just below the other headers in the beginning of the file.

Go to SFML/Window/Win32/WglContext.hpp and make this function public:
// ...
public:
void createSurface(HWND window, unsigned int bitsPerPixel);
private:
// ...
 

Then, simply change the beginning of this function:
////////////////////////////////////////////////////////////
void Window::create(VideoMode mode, const String& title, Uint32 style, const ContextSettings& settings)
{
        if (m_context)
        {
                delete m_impl;
                m_impl = priv::WindowImpl::create(mode, title, style, settings);
                auto ptr = (sf::priv::WglContext*)m_context;
                ptr->createSurface(m_impl->getSystemHandle(), mode.bitsPerPixel);
                wglMakeCurrent(ptr->m_deviceContext, ptr->m_context);
                initialize();
                return;
        }
        // ...
 

I also noticed that a point for improvement for SFML is remembering the previous state of mouse grabbed, visibility, etc.

Obviously, this is a workaround, and not very pretty. Note that this adaption skips some tests done later in the function, like validating the window's style.

I expect SFML to support this natively in the future, where each platform-specific implementation does its thing.

Cya.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11032
    • View Profile
    • development blog
    • Email
Re: [Tutorial] How to Recreate Window without destroying the Context
« Reply #1 on: January 10, 2024, 08:29:12 am »
Can't you achieve the same by creating your own sf::Context?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Powereleven

  • Newbie
  • *
  • Posts: 36
    • View Profile
Re: [Tutorial] How to Recreate Window without destroying the Context
« Reply #2 on: January 10, 2024, 03:45:23 pm »
I never managed to achieve this using only sf::Context. Maybe it has something to do with incompatible "pixel format" internally?

Digging deeper, I think the following has something to do with it:

In void WglContext::createSurface(HWND window, unsigned int bitsPerPixel), m_deviceContext is updated to a kind of handle to the Win32 window: m_deviceContext = GetDC(window);. This is probably necessary, as window.display() calls SwapBuffers with m_deviceContext as a parameter.

Then, if you use window.create without my changes, it additionally calls void WglContext::createContext(WglContext* shared) in the constructor of WglContext, which calls m_context = wglCreateContextAttribsARB(m_deviceContext, sharedContext, &attributes[0]);, recreating the internal OpenGL context handle HGLRC m_context of WglContext. My adaptation keeps the same HGLRC on the new window.