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

Author Topic: Vsync enforced before draw methods instead of display  (Read 909 times)

0 Members and 1 Guest are viewing this topic.

sprkrd

  • Newbie
  • *
  • Posts: 2
    • View Profile
Vsync enforced before draw methods instead of display
« on: May 30, 2023, 07:33:47 pm »
Hello!

This post [1] from many years ago didn't receive much attention, but I'm experiencing the same issues described there: Vsync delays seem to be enforced before the in the first call to draw or clear, rather than in the call to display.

This is causing me problems because in my application I want to separate rendering from the physics updates. The rendering thread locks the environment (mutex) while drawing, and unlocks it before the call to win.display(). The physics thread locks the environment during the world updates. This way, the rendering thread won't draw an object while it's being updated by the physics engine. Physics updates take negligible time. Drawing should also take very little time, under the premise that vsync delays are introduced by the display method rather than the drawing methods. However, that's not the case, and the rendering thread locks the environment during the entire time taken by a single frame (~16 ms @ 60 hz), forcing more than one physics update per iteration of the game loop.

I could probably do without locking, it doesn't matter much to me that a frame is rendered in the middle of an update. It's also more or less fine doing more than one physics update per iteration, but in that case the same input is used twice (not terribly important either, but it defeats the purpose of multi-threading). I don't want to settle with any of these two solutions. I'm a bit obsessive and I like to have as much control over what happens as possible.

My code is a bit too complex to post a snippet here, but I took the code (introducing minor modifications) from the linked post (with no threading involved). Indeed, the first call to clear during each iteration takes approximately 16 ms. If I'm misinterpreting the results, could you please tell me how?

#include <iostream>
#include <vector>

#include <SFML/Graphics.hpp>

int main(int argc, char* argv[]) {
  sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Render window");
  window.setVerticalSyncEnabled(true);

  sf::RectangleShape rr(sf::Vector2f(20.f, 20.f));

  while (window.isOpen()) {
    sf::Event evt;
    while (window.pollEvent(evt)) {
      if (evt.type == sf::Event::Closed)
        window.close();
    }
    sf::Clock clock;

    window.clear(sf::Color::Blue);
    double time0 = clock.restart().asSeconds();
    std::cout << "0: " << time0 << std::endl;

    rr.setPosition(0, 0);
    window.draw(rr);

    double time1 = clock.restart().asSeconds();
    std::cout << "1: " << time1 << std::endl;

    rr.setPosition(20, 20);

    window.draw(rr);

    double time2 = clock.restart().asSeconds();
    std::cout << "2: " << time2 << std::endl;

    window.display();

    double time3 = clock.restart().asSeconds();
    std::cout << "3: " << time3 << std::endl;

  }

  return 0;
}
 

Example output:

0: 0.016284
1: 0.000124
2: 3.2e-05
3: 0.000258
0: 0.016203
1: 0.000161
2: 4.2e-05
3: 0.000363

[1] https://en.sfml-dev.org/forums/index.php?topic=14210
« Last Edit: May 30, 2023, 07:35:28 pm by sprkrd »

kojack

  • Sr. Member
  • ****
  • Posts: 330
  • C++/C# game dev teacher.
    • View Profile
Re: Vsync enforced before draw methods instead of display
« Reply #1 on: May 31, 2023, 07:08:08 am »
There's a stack overflow answer to this (not sfml related, but same cause) here: https://stackoverflow.com/a/24136893

Basically the display call uses SwapBuffers (I'm talking about on Windows). This may not block, it returns immediately, queuing the swap to actually happen at the right time (vsync) in the background. Any rendering operation then executed after the swap but before the swap has internally completed will block.
So your 16ms clear calls are actually waiting for the previous swapbuffers to finish.

I guess the quick hack would be to do something simple immediately after the display to force it to block then. Maybe move the clear call to there.

sprkrd

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: Vsync enforced before draw methods instead of display
« Reply #2 on: May 31, 2023, 11:55:02 am »
There's a stack overflow answer to this (not sfml related, but same cause) here: https://stackoverflow.com/a/24136893

Basically the display call uses SwapBuffers (I'm talking about on Windows). This may not block, it returns immediately, queuing the swap to actually happen at the right time (vsync) in the background. Any rendering operation then executed after the swap but before the swap has internally completed will block.
So your 16ms clear calls are actually waiting for the previous swapbuffers to finish.

I guess the quick hack would be to do something simple immediately after the display to force it to block then. Maybe move the clear call to there.

Thank you!

That clarifies a lot, now I can finally understand what's happening.

Just after your post I came up with an idea similar to yours. Instead of clearing after the display, I do a win.clear() before locking the mutex, then lock the mutex and draw everything (at this point the drawing methods don't block), and finally I unlock the mutex and call win.display().