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

Author Topic: Ability to toggle fullscreen mode during runtime  (Read 17267 times)

0 Members and 1 Guest are viewing this topic.

Unarelith

  • Newbie
  • *
  • Posts: 8
    • View Profile
Ability to toggle fullscreen mode during runtime
« on: May 12, 2020, 02:49:06 am »
Hello,

The search feature of this forum is currently broken on my end so I don't know if anybody already posted this request.

However, I found those issues:

When using SFML for an OpenGL program (so, without using sf::RenderWindow) the only way to switch to fullscreen mode is to recreate the window.

This may not be a problem when using sf::RenderWindow because this class probably saves the OpenGL state and is able to restore it when the window is recreated.

However, when using sf::Window, users will have to save the paramters sent to sf::Window::create() + the current OpenGL state (calls to glEnable/glDisable/glClearColor and probably other things).

This is a real problem because it causes obscure bugs, and imo it shouldn't be up to the users to deal with that.

What is your opinion on that matter?

EDIT: Minimal example for glClearColor:

#include <SFML/OpenGL.hpp>
#include <SFML/Window.hpp>

int main(int, char **) {
        sf::ContextSettings settings;
        settings.depthBits = 24;
        settings.stencilBits = 8;
        settings.antialiasingLevel = 0;
        settings.majorVersion = 2;
        settings.minorVersion = 1;

        sf::Window window;
        window.create(sf::VideoMode(800, 600), "OpenGL", sf::Style::Close, settings);
        auto desktop = sf::VideoMode::getDesktopMode();
        window.setPosition(sf::Vector2i(
                desktop.width / 2 - window.getSize().x / 2,
                desktop.height / 2 - window.getSize().y / 2
        ));

        glClearColor(0.0f, 1.0f, 1.0f, 1.0f);

        bool running = true;
        bool fullscreen = false;
        while (running) {
                sf::Event event;
                while (window.pollEvent(event)) {
                        if (event.type == sf::Event::Closed || (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape)) {
                                running = false;
                        }
                        else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::A) {
                                window.create(sf::VideoMode(800, 600), "OpenGL", sf::Style::Close, settings);
                        }
                        else if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Z) {
                                window.create(sf::VideoMode(800, 600), "OpenGL", sf::Style::Close, settings);

                                auto desktop = sf::VideoMode::getDesktopMode();
                                window.setPosition(sf::Vector2i(
                                        desktop.width / 2 - window.getSize().x / 2,
                                        desktop.height / 2 - window.getSize().y / 2
                                ));

                                glClearColor(0.0f, 1.0f, 1.0f, 1.0f);
                        }
                }

                glClear(GL_COLOR_BUFFER_BIT);

                window.display();
        }

        window.close();

        return 0;
}

When you press 'A', the window is recreated but nothing is setup, so it resets to its original position and the clear color goes back to black.
When you press 'Z', the window is recreated but both the position and the clear color are setup again so it's fine.

However, I don't think the user should have to store and re-setup all those things (position, video mode, caption, style, context settings, glEnable/Disable/ClearColor, etc...).
« Last Edit: May 12, 2020, 09:12:16 am by Quent42340 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Ability to toggle fullscreen mode during runtime
« Reply #1 on: May 12, 2020, 08:13:07 am »
Have you actually tried it before posting, and experienced the issues you describe?
Laurent Gomila - SFML developer

Unarelith

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Ability to toggle fullscreen mode during runtime
« Reply #2 on: May 12, 2020, 08:28:28 am »
Of course I did.

What I said about glEnable/glDisable/glClearColor is verified, and there is other obscure bugs I don't completely understand yet. I'll dig into them later today.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Ability to toggle fullscreen mode during runtime
« Reply #3 on: May 12, 2020, 09:49:06 am »
It is not supposed to happen, because SFML always keeps an active OpenGL context, and states are shared among all contexts, so that you never lose anything even if you recreate the window and its context.

Maybe glEnable/glDisable/glClearColor are not shared and are lost anyway. I don't remember, the last time I checked was a long time ago.

We'd need binary1248 for fresh information on this subject ;D
Laurent Gomila - SFML developer

Unarelith

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Ability to toggle fullscreen mode during runtime
« Reply #4 on: May 12, 2020, 10:01:19 am »
Yes, hopefully it keeps the OpenGL context, so my textures/VBO/VAO/shaders seems fine after window re-creation.

The fact that those states aren't shared is one of the issues, yes. However I've one more problem but I didn't dig into it yet, and I don't think this is related to glEnable/glDisable/glClearColor so I'll post more infos here when I'll have the time to debug it (probably today)

The symptom I noticed is glUniform4fv calls failure + black screen after toggling fullscreen mode on a 2D-only game state (using my own 2D rendering code, not the Graphics module).

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11034
    • View Profile
    • development blog
    • Email
Re: Ability to toggle fullscreen mode during runtime
« Reply #5 on: May 12, 2020, 01:31:08 pm »
SFML only ensures its own states, since it can't know of your custom states, as such it's your responsibility to keep track of your own states.

The search feature of this forum is currently broken on my end so I don't know if anybody already posted this request.
I'm still working on this, but don't forget that you can just google search the forum as well with the site:en.sfml-dev.org appended to your text query. ;)
« Last Edit: May 12, 2020, 01:36:49 pm by eXpl0it3r »
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Unarelith

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Ability to toggle fullscreen mode during runtime
« Reply #6 on: May 12, 2020, 05:03:41 pm »
SFML only ensures its own states, since it can't know of your custom states, as such it's your responsibility to keep track of your own states.
Yep, that's why I'm requesting for a feature to toggle fullscreen mode during runtime, because this is the right way to fix this problem. Users shouldn't have to keep track of their OpenGL state.

glfw, SDL and most of the window/OS event management libraries I know are capable of setting a window to fullscreen, I don't understand why SFML can't.

I'm still working on this, but don't forget that you can just google search the forum as well with the site:en.sfml-dev.org appended to your text query. ;)
Oh right! I didn't think about that haha


That being said, I've been trying to debug the glUniformMatrix4fv issue all day, no progress so far.
I get a GL_INVALID_OPERATION code on these calls, but I can't find the origin of the problem, and there's many many possibilities: https://www.khronos.org/registry/OpenGL-Refpages/gl4/html/glUniform.xhtml#errors

This bug is weird because:
  • It used to work perfectly using SDL
  • Only the title screen is impacted, other game states (that share the exact same rendering code) are not impacted
  • When I click blindly on a title screen button during black screen, the new state (ex settings menu) will render properly, and if I back to title screen, the title screen will render properly too

The error is vague, and I just can't find what could cause it.

And all of this (glEnable/glDisable/glClearColor + GL_INVALID_OPERATION) is because of the lack of a proper way to toggle fullscreen mode.
« Last Edit: May 12, 2020, 06:08:45 pm by Quent42340 »

Unarelith

  • Newbie
  • *
  • Posts: 8
    • View Profile
Re: Ability to toggle fullscreen mode during runtime
« Reply #7 on: May 12, 2020, 07:57:50 pm »
Ok so I found out why I had this weird behaviour with glUniformMatrix4fv.

The OpenGL context doesn't keep bound shaders, and since I don't bind already bound shaders, it considers that nothing is bound.
This is another important issue imo.

Kasufert

  • Newbie
  • *
  • Posts: 1
    • View Profile
    • Email
Re: Ability to toggle fullscreen mode during runtime
« Reply #8 on: February 24, 2024, 05:55:56 pm »
SFML only ensures its own states, since it can't know of your custom states, as such it's your responsibility to keep track of your own states.
Yep, that's why I'm requesting for a feature to toggle fullscreen mode during runtime, because this is the right way to fix this problem. Users shouldn't have to keep track of their OpenGL state.

glfw, SDL and most of the window/OS event management libraries I know are capable of setting a window to fullscreen, I don't understand why SFML can't.
[/quote]


I found this on The Old New Thing and it works as a nice toggle while maintaining all OpenGL state:

void ToggleFullscreen(sf::Window& window, WINDOWPLACEMENT& g_wpPrev)
{
#ifdef WINDOWS
    sf::WindowHandle hwnd = window.getSystemHandle();
    DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
    if (dwStyle & WS_OVERLAPPEDWINDOW) {
        MONITORINFO mi = { sizeof(mi) };
        if (GetWindowPlacement(hwnd, &g_wpPrev) &&
            GetMonitorInfo(MonitorFromWindow(hwnd,
                MONITOR_DEFAULTTOPRIMARY), &mi)) {
            SetWindowLong(hwnd, GWL_STYLE,
                dwStyle & ~WS_OVERLAPPEDWINDOW);
            SetWindowPos(hwnd, HWND_TOP,
                mi.rcMonitor.left, mi.rcMonitor.top,
                mi.rcMonitor.right - mi.rcMonitor.left,
                mi.rcMonitor.bottom - mi.rcMonitor.top,
                SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
        }
    }
    else {
        SetWindowLong(hwnd, GWL_STYLE,
            dwStyle | WS_OVERLAPPEDWINDOW);
        SetWindowPlacement(hwnd, &g_wpPrev);
        SetWindowPos(hwnd, NULL, 0, 0, 0, 0,
            SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
            SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
    }
#endif
}
 

If you couldn't tell, it is Windows only, but it is quite fast. The only additional setup you need is to keep track of a WINDOWPLACEMENT variable and initialize it with

    g_wpPrev.length = sizeof(WINDOWPLACEMENT);
    GetWindowPlacement(window.getSystemHandle(), &g_wpPrev);
 

after creating your window.