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?
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;
}