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

Author Topic: Hitching and Crashing with multiple sf::Window handles  (Read 3774 times)

0 Members and 1 Guest are viewing this topic.

Ant

  • Newbie
  • *
  • Posts: 28
    • View Profile
    • Email
Hitching and Crashing with multiple sf::Window handles
« on: June 05, 2020, 11:17:58 pm »
I've been experiencing hitches with sf::Window::pollEvents function. Most of the time, the application can run smoothly (over 100 fps). But every few seconds, the app hitches on this function.

    Stopwatch pollEventsStopwatch;

    int counter = 0;

    sf::Event sfEvent;
    while (Resource != nullptr && Resource->pollEvent(sfEvent))
    {
        counter++;

        //Do stuff in this loop, but this loop is never iterating since there aren't any events.
    }

    FLOAT elapsedTime = pollEventsStopwatch.GetElapsedTime();
    if (elapsedTime > 50)
    {
        int breakHere = 0; //<----  I'm hitting this breakpoint since elapsed time is usually above 150 milliseconds even when counter is 0.
    }
 

I've been struggling with this for awhile. The best theory I have is maybe because there many window handles in this application. The application I have is basically runs multiple unit tests so it pops up about five windows on a thread. And to test this theory, I closed all but one of the windows. And it seems to never hit that break point when it's down to one window handle.

I tried moving one of the tests to its own thread, but by doing so, I'm running into a new issue where creating a new window handle on the separate thread causes an infinite recursion crash.

//Other stuff here. Let me know if you want me to post the full context of this function.

PrimaryWindow = Window::CreateObject();
PrimaryWindow->SetResource(new sf::RenderWindow(sf::VideoMode(800, 600), PROJECT_NAME)); //<---- crashes here
 

Callstack crash:
....
        sfml-window-d-2.dll!`anonymous namespace'::getInternalContext() Line 159        C++
        sfml-window-d-2.dll!sf::priv::GlContext::ensureContext() Line 217       C++
        sfml-window-d-2.dll!sf::GlResource::GlResource() Line 61        C++
        sfml-window-d-2.dll!sf::Context::Context() Line 61      C++
        sfml-window-d-2.dll!`anonymous namespace'::getInternalContext() Line 159        C++
        sfml-window-d-2.dll!sf::priv::GlContext::ensureContext() Line 217       C++
        sfml-window-d-2.dll!sf::GlResource::GlResource() Line 61        C++
        sfml-window-d-2.dll!sf::Context::Context() Line 61      C++
        sfml-window-d-2.dll!`anonymous namespace'::getInternalContext() Line 159        C++
        sfml-window-d-2.dll!sf::priv::GlContext::ensureContext() Line 217       C++
        sfml-window-d-2.dll!sf::GlResource::GlResource() Line 61        C++
        sfml-window-d-2.dll!sf::Context::Context() Line 61      C++
....
 

While reading through docs and forums, I learned about sf::Window::setActive. Although I call setActive(true) during the draw/render stage, it did not seem to make a difference. Then I started calling setActive(false) everywhere (after creating sf::RenderWindow, before render calls, before pollEvents, etc...). I know that's not the right way of doing things, but I was hoping it would at least 'lock' the windows instead of crashing whenever I create a window handle on a different thread.

I've did this for sf::RenderTextures, too. And I'm still crashing whenever I create a window handler on the other thread.


And here I am currently stuck. I'm running SFML version 2.4.0. I suppose I can upgrade it to a later version in case there was a bug fix for this.


Questions I have are:
1. Any idea why polling events sometimes take over 150 milliseconds even though there aren't any events?

2. When do I need to call setActive on a window handle? Can it only be activated before calling clear, draw, display functions? Or do I need to activate the window handles when polling events, too? I presume the same should be done for sf::RenderTextures, too.

3. Any idea what could be causing the infinite recursion crash? If the windows are self contained in their own threads, is it possible to handle windows and render textures in multiple threads if setActive is called appropriately?

Ant

  • Newbie
  • *
  • Posts: 28
    • View Profile
    • Email
Re: Hitching and Crashing with multiple sf::Window handles
« Reply #1 on: June 07, 2020, 10:52:01 pm »
Update

I've disabled nearly everything from the main thread. It's essentially ticking an empty loop. It doesn't create any windows nor does it create any RenderTextures.

This allowed my second thread to create window handles.

I've also minimized that thread to display a blank window. It only has a mouse pointer in a blank screen.

Some things I observed from this.
1. I'm still reaching 100-175 ms on an empty pollEvents loop.
2. Moving tests to a separate thread will not fix my hitching problem.
3. Calling setActive(false) to everything doesn't seem to do anything. The window handles are still rendering a sprite even when I set its active to false. In fact, I'm setting it to be inactive every poll event.
        std::vector<sf::Event> events;
        if (Resource != nullptr)
        {
                const std::lock_guard<std::mutex> lock(WindowResourceMutex);
                Resource->setActive(false);

                Stopwatch pollEventStopwatch(TXT("windowStopwatch"), false);

                sf::Event sfEvent;
                while (Resource->pollEvent(OUT sfEvent))
                {
                        //Do stuff in loop.
                        events.push_back(sfEvent);
                }

                FLOAT elapsedTime = pollEventStopwatch.GetElapsedTime();
                if (elapsedTime > 50)
                {
                        int breakHere = 0; //Hitting this breakpoint
                }
        }
        //Registered callbacks will handle events, but those are outside the scope of stopwatch, and the events vector is empty.
 

I started to suspect the hitches could be related to cache misses, but when I debugged the entire tick cycle, I'm only hitting 50+ ms on the system tick group.

        //Update all TickGroups and their registered TickComponents
        for (TickGroup* tickGroup : TickGroups)
        {
                Stopwatch tickGroupStopwatch(TXT("TickGroupStopwatch"), false);
                tickGroup->TickRegisteredComponents(deltaSec);
                FLOAT elapsedTime = tickGroupStopwatch.GetElapsedTime();
                if (elapsedTime > 50 && !IsMainEngine())
                {
                        int breakHere = 0; //<---- I'm hitting this break point from time-to-time on the System tick group.
                }
        }
 

In this test, there are numerous tick groups: Debug, Render, Gui, etc...
None of those tick groups are triggering that break point. Only the System tick group is hitting that break point. And there is only one registered TickComponent in that group and that is for handling the window poll events, which is also pasted above.


I've ran the Hello World SFML project, and I'm not hitting that break point. That program seems to run smoothly.
int main()
{
    sf::RenderWindow window(sf::VideoMode(200, 200), "SFML works!");
    sf::CircleShape shape(100.f);
    shape.setOrigin(100.f, 100.f);
    shape.setPosition(100.f, 100.f);
    shape.setFillColor(sf::Color::Green);

    while (window.isOpen())
    {
                std::clock_t c_start = std::clock();
                auto t_start = std::chrono::high_resolution_clock::now();
                std::vector<sf::Event> evnts;

        sf::Event event;
        while (window.pollEvent(event))
        {
                        evnts.push_back(event);
            if (event.type == sf::Event::Closed)
                window.close();
        }

        window.clear();
        window.draw(shape);
        window.display();

                std::clock_t c_end = std::clock();
                auto t_end = std::chrono::high_resolution_clock::now();
                double elapsedTime = 1000.0 * (c_end-c_start) / CLOCKS_PER_SEC;
                if (elapsedTime > 50)
                {
                        int breakHere = 0; //<----- I am NOT hitting this breakpoint
                }
    }

    return 0;
}
 

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10815
    • View Profile
    • development blog
    • Email
Re: Hitching and Crashing with multiple sf::Window handles
« Reply #2 on: June 07, 2020, 11:43:57 pm »
You should really be focusing on one thing at a time.

If pollEvent() "hangs" for a long time, it has nothing to do with OpenGL and setActive, because non of that is involved in pollEvent(). What's more likely the cause is some faulty input device driver.
Check that you have the official drivers installed for your input devices and that you're not using any weird gamepads/joysticks that identify themselves oddly.
Measuring and breaking after it happens is fine to detect that issue, but if you really want to figure out what's going on, you should use a profiler. It's still tricky to capture it, but it may give you an insight where it spends a lot of time.

As for your multiple sf::Window handles. What do you mean with multiple sf::Window handles? What's a handle for you?
Don't forget that you can process events only in the thread that created the window.
Also remember that writing multi-threaded code introduces a lot of complexity and with it a lot of hard to understand and hard to debug problems. Don't do it unless you have a good reason and enough experience.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Ant

  • Newbie
  • *
  • Posts: 28
    • View Profile
    • Email
Re: Hitching and Crashing with multiple sf::Window handles
« Reply #3 on: June 08, 2020, 12:49:12 am »
Quote
You should really be focusing on one thing at a time.
I agree. My main focus is to figure out how to fix the hitches. My investigation lead me to many irrelevant things such as the setActive.

Quote
What's more likely the cause is some faulty input device driver.
That's a fantastic idea! I'll check my hardware and their drivers tonight.

Quote
Measuring and breaking after it happens is fine to detect that issue, but if you really want to figure out what's going on, you should use a profiler. It's still tricky to capture it, but it may give you an insight where it spends a lot of time.
I'll have to research more about this. I'm not familiar with using a profiler.


Quote
As for your multiple sf::Window handles. What do you mean with multiple sf::Window handles? What's a handle for you?
A handle to me is similar to Window API HWND. But instead of void*, I'm treating sf::Window as the object that interfaces with the OS.
In my case, I really have multiple sf::Window instances. One thread use to have three window handles, and another thread is responsible for 2. Now I'm down to a single sf::Window instance that resides in a separate thread.

Quote
Don't forget that you can process events only in the thread that created the window.
Yeah I read that from somewhere. Probably from the docs or from another help forum. The good news is that the thread is very isolated from everything else. The thread creates its own copy of the engine. It imports its own textures and fonts. It creates its own sf::Window, poll handlers, input handlers, tick groups, etc...

Threads are only allowed to communicate through ThreadedComponents, but there aren't any instantiated in this test. The only exception is the shutdown signal, and maybe a few static variables for mutex locks.

Quote
Also remember that writing multi-threaded code introduces a lot of complexity and with it a lot of hard to understand and hard to debug problems. Don't do it unless you have a good reason and enough experience.
Yeah. Race conditions really scare me. I plan to write multi-threaded code for heavy processing that could be extracted from the main thread. I only moved this test to a separate thread to see if having too many sf::Window instances on the same thread is problematic.

Ant

  • Newbie
  • *
  • Posts: 28
    • View Profile
    • Email
Re: Hitching and Crashing with multiple sf::Window handles
« Reply #4 on: June 09, 2020, 12:42:59 am »
Update

I've updated my drivers and did a full restart on my machine. That seem to solve my issue. The test is now very smooth!

Though I'm curious. If it was a driver/OS issue, I don't understand why other applications were not hitching. When playing resource intensive games like GW2, that game seems to run smoothly but yet my simple sprite render test hitches.

I've also did some experimenting this morning. Although it's no where near as prevalent as before I was able to cause a few hitches when running other programs like Process Explorer. But it's no where as bad as it was. Before it was hitting 150+ ms every 2-5 seconds. During my experiments this morning, it would hit 60-75 ms once every few minutes (only when Process Explorer's system monitor was running). When running a blank desktop, I never got it to hit that break point.

I guess I can close this ticket out since it may appear negligible. I have lingering worries when I do decide to upscale my project to include a physics engine and render more Entities. I have a feeling the hitching would come back, and it'll be more difficult to debug and fix once the project becomes even more complicated.