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

Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - espectra

Pages: [1]
1
Asking for "vsync" is a request to the driver. There is no guarantee it will (or can) be honored.
You need to ensure that a) your logic updates are decoupled from your rendering. b) your rendering is independent of your framerate. c) realize that you can't get "vsync" everywhere (does it even make sense for modern lcd panels rhat don't actually have a vertical retrace like old CRT monitors?).
Vsync makes sense if you have a tearing problem. Don't think of it as a "fix framerate limit" thing. If you need to fix (somewhat) your framerate, you need to implement sleeps that make you render at roughly the framerate you want (and handle the inacuracies). Don't rely on vsync for that.

This is good info! Thanks.

About the "modern lcd" not having vsync, that's an interesting topic. Aren't most displays actually LED displays these days?

Anyway, regardless of whether vsync works on my notebook's built-in display, I've never really seen tearing on it.

However, when testing on a friend's desktop PC with external LED display, I've seen some obvious tearing happening with the same test program.

Since I kind of enjoy understanding the technical stuff like this, I'd like to learn what's going on between testing the program on my notebook and on a desktop. For instance, the Intel media control panel on my notebook has a Vertical Sync option which can be set to "Application Settings" or "On". I don't know if that applies to DirectX only or also OpenGL, since it basically hides some of that underlying detail from the user (older versions of the Intel Graphics drivers seemed to show OpenGL settings explicitly...)

I wonder if we could come up with a simple test case that includes the features you mentioned (decoupled logic and rendering, framerate independent rendering) to show how the setting of vsync (wglSwapIntervalEXT) affects everything?

2
Probably it will be better to rename SetVerticalSync to SetSwapInterval to avoid confusing. There is no way to control vblank sync with OpenGL.

But you tested it on OpenGL 4.1 and reported that it worked, didn't you?

May be it's related with OpenGL version, here is my observations:

OpenGL 4.5: vblank sync works OK
OpenGL 2.1: vblank sync didn't works

This whole thing with vsync & OpenGL is very confusing.  :o

3
May be it's related with OpenGL version, here is my observations:

OpenGL 4.5: vblank sync works OK
OpenGL 2.1: vblank sync didn't works

It's quite strange - the OpenGL driver on my PC only supports 2.1, but apparently for Windows, OpenGL uses a Windows-specific extension to set vsync: the wglSwapIntervalEXT extension. My driver DOES support that and indeed SFML gets the extension and uses it, by setting the swap interval to 1 when setVerticalSyncEnabled() is set to true.

I'm not yet sure if it's actually enabling vsync and preventing tearing, but it definitely seems to NOT be limiting the frame rate to the refresh rate of 60Hz. Same problem with LWJGL, so I doubt it's simply an SFML problem.

I don't know what's going on and googling info is pretty frustrating and not turning up anything useful.

4
The problem is that on my notebook PC, using setVerticalSyncEnabled(true) doesn't limit the framerate to the refresh rate (60Hz).

It seems that it's because there is an issue with SFML. I have the same issue on Windows 10 machine.
With SFML setting VerticalBlankSync(true) just doesn't works on this machine.
But I can run my DirectX application on the same machine and it can use vblank sync with no problem (and I see that it really works on the timing realtime graph)...
But when I trying to enable it from SFML application, vblank sync just has no effect (it runs with 1000 fps).

May be it's related to specific driver or OpenGL...

I did an experiment yesterday with Slick2D/LWJGL which uses OpenGL and it had the same problem, so it may be an OpenGL driver problem, either just with my driver or possibly also the OpenGL drivers for other GPUs.

FWIW my notebook has a built-in Intel graphics accelerator, "Mobile Intel 4 Series Express" and the driver is the latest version but since it's an old PC (2009), the latest driver update is from 2013 and it only supports up to OpenGL 2.1.

For now in my prototype game I'm just using setFramerateLimit(). There's no tearing on the notebook, but I plan to check it on a friend's PC with an Nvidia GPU to see if I need to do something to prevent tearing.

5
If you try an OpenGL based game, can you go into fullscreen mode for the same resolution?

Also go to Intel's website and make sure that your GPU driver is uptodate.

Yes, my previous game was built with LWJGL and works in fullscreen mode at 1280x800 (my PC's default resolution). It also works in both "separate fullscreen" and "borderless window on desktop fullscreen" modes, with the former being the default when changing to fullscreen in LWJGL and the latter being achieved with a "no decoration" flag if I recall correctly.

Anyway, I edited my reply to Laurent to note that I can make the fullscreen mode change succeed if SFML passes the frequency in the ChangeDisplaySettings() Windows call, although it's really just a borderless fullscreen window still "on" the desktop. The only difference between that and a "separate from desktop" fullscreen would be how alt-tab works (no big deal) and whether a separate mode would make vsync start working for me.

I may search through the LWJGL native Windows code to see if they're doing the mode change slightly differently than SFML does it. Seems like it's only a problem for my PC and possibly other Intel graphics notebooks I guess.

6
getFullscreenModes()[0] is not guaranteed to be the desktop mode. There's getDesktopMode() for that.

Other than that, I see nothing wrong in your code. I guess we could make the error output more verbose, it doesn't help much.

Thanks!

I changed it to use getDesktopMode() and it gives the same error, unfortunately.

So I added a couple of lines to the SFML source, WindowImplWin32.cpp to print out a bit of info just to verify what options it's passing to the ChangeDisplaySettingsW() call and I get this as error output:

Failed to change display mode for fullscreen
More info:
   width=1280 height=800 BitsPerPel=32 Fields=1c0000
 

which corresponds to the default desktop parameters Windows is using on my PC, and I guess the fields are just bits to tell ChangeDisplaySettingsW() which fields it's passing.

I'm reading the Windows ChangeDisplaySettings() docs now to try and get an error code from the call. I'll update when/if I figure something out.

UPDATE: Ok, adding the frequency in the call to ChangeDisplaySettingsW() fixes the problem.

Well, sort of -- the call works and it opens fullscreen, but it's a borderless fullscreen window still on the desktop. Hard to explain, but most gamers and devs will know, i.e. hitting alt-tab takes you to the previous OS window with the game still visible in the background.

Whereas the "separate fullscreen" mode would take you to the previous OS window without the game visibile in the background.

Not a big deal. The main reason I'm looking into all this is that I still can't get vertical sync to work on my PC as I detailed in this post: http://en.sfml-dev.org/forums/index.php?topic=19082.0

I'll keep experimenting with this.

Here's the change I made to WindowImplWin32::switchToFullscreen() BTW

void WindowImplWin32::switchToFullscreen(const VideoMode& mode)
{
    DEVMODE devMode;
    devMode.dmSize       = sizeof(devMode);
    devMode.dmPelsWidth  = mode.width;
    devMode.dmPelsHeight = mode.height;
    devMode.dmBitsPerPel = mode.bitsPerPixel;
    //devMode.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL;
    // Also pass frequency
    devMode.dmDisplayFrequency = 60;
    devMode.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;

    // Change Display and get error code if any
    long code;
    code = ChangeDisplaySettingsW(&devMode, CDS_FULLSCREEN);

    // Apply fullscreen mode
    if (
        //ChangeDisplaySettingsW(&devMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL
        code != DISP_CHANGE_SUCCESSFUL
        )
    {
        err() << "Failed to change display mode for fullscreen" << std::endl;

        err() << "More info:\n";
        err() << "   width=" << mode.width << " height=" << mode.height <<
                      " BitsPerPel=" << mode.bitsPerPixel << " Fields=" << std::hex <<
                      (devMode.dmFields) << std::endl;

        switch(code) {
        case DISP_CHANGE_SUCCESSFUL:
          err() << "        DISP_CHANGE_SUCCESSFUL\n"; break;
        case DISP_CHANGE_BADDUALVIEW:
          err() << "        DISP_CHANGE_BADDUALVIEW\n"; break;
        case DISP_CHANGE_BADFLAGS:
          err() << "        DISP_CHANGE_BADFLAGS\n"; break;
        case DISP_CHANGE_BADMODE:
          err() << "        DISP_CHANGE_BADMODE\n"; break;
        case DISP_CHANGE_BADPARAM:
          err() << "        DISP_CHANGE_BADPARAM\n"; break;
        case DISP_CHANGE_FAILED:
          err() << "        DISP_CHANGE_FAILED\n"; break;
        case DISP_CHANGE_NOTUPDATED:
          err() << "        DISP_CHANGE_NOTUPDATED\n"; break;
        case DISP_CHANGE_RESTART:
          err() << "        DISP_CHANGE_RESTART\n"; break;
        default:
          err() << "        unrecognized error...\n"; break;
        }

        return;
    }

    // Make the window flags compatible with fullscreen mode
    SetWindowLongW(m_handle, GWL_STYLE, WS_POPUP | WS_CLIPCHILDREN | WS_CLIPSIBLINGS);
    SetWindowLongW(m_handle, GWL_EXSTYLE, WS_EX_APPWINDOW);

    // Resize the window so that it fits the entire screen
    SetWindowPos(m_handle, HWND_TOP, 0, 0, mode.width, mode.height, SWP_FRAMECHANGED);
    ShowWindow(m_handle, SW_SHOW);

    // Set "this" as the current fullscreen window
    fullscreenWindow = this;
}

 

7
Should this test program below succeed at opening a "window" in fullscreen mode with the same attributes as the current desktop mode? (When I write "window", I mean a fullscreen OpenlGL surface separate from the OS'es desktop.

This is on an hp dv4 notebook PC running Windows Vista. GPU is Mobile Intel 4 Series Express chipset. And I'm using SFML 2.3.1

When I run it, it opens a regular window with titlebar on the desktop and the output has red log info:

"Failed to change display mode for fullscreen"

//
// Test opening a fullscreen window on my hp dv4 laptop
//

#include <SFML/Graphics.hpp>

int main()
{
  // Create a fullscreen window
  sf::RenderWindow renderWindow(sf::VideoMode::getFullscreenModes()[0],"Test", sf::Style::Fullscreen);

  // set up a multi-colored quad
  sf::VertexArray quad(sf::Quads, 4);
  quad[0].position = sf::Vector2f(100,100);
  quad[1].position = sf::Vector2f(200,100);
  quad[2].position = sf::Vector2f(200,200);
  quad[3].position = sf::Vector2f(100,200);

  quad[0].color = sf::Color::Blue;
  quad[1].color = sf::Color::Red;
  quad[2].color = sf::Color::Green;
  quad[3].color = sf::Color::White;

  // ********************************************************************************************************************
  // Start the "game" loop
  // ********************************************************************************************************************
  while (renderWindow.isOpen())
  {

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) {
          renderWindow.close();
    }

    sf::Event event;
    while (renderWindow.pollEvent(event)) {
        // DO NOTHING
    }

    renderWindow.clear(sf::Color::Black);
    renderWindow.draw(quad);
    renderWindow.display();

  }
  return EXIT_SUCCESS;
}
 

I've been able to switch to fullscreen mode in past projects (using LWJGL), so I doubt it's an OpenGL driver problem.

Am I screwing up something obvious?

8
Remember that even with vsync (when it's even available, it isn't always) you are not guaranteed a completely stable framerate. You always have to take into account that time-per-frame can vary and decouple your game logic updates from your rendering. And once you do that, setting a framerate limit is usually just as fine as using vsync (unless you have tearing problems specifically).
Just don't mix the two.


Hmm, this is interesting because I'm mixing the two. But you're right - the tutorial says not to mix them. It's just that for my PC, mixing them doesn't make things worse. It makes them better.  :P

The problem is that on my notebook PC, using setVerticalSyncEnabled(true) doesn't limit the framerate to the refresh rate (60Hz).

Not sure if it's the correct place to check and set this, but in the "Intel Graphics and Media Control Panel" there IS an option under 3D relating to Vertical Sync. It's currently set to "Application Settings" which I assume means SFML would enable/disable it according to my setting with setVerticalSyncEnabled().

The other option is "On", but changing to that and clicking Apply still doesn't limit the framerate in my game.

That's why I'm currently using both setVerticalSyncEnabled(true) to prevent tearing AND setFramerateLimit(60) to keep from hogging the CPU.

Of course my PC may be quite different from what most of you guys are using, but a medium powered notebook PC is pretty useful in game dev since many of your players/customers will only have a medium powered PC.

Anyway, is this a known issue/situation where some notebook PCs don't allow vsync (at least with SFML)?

EDIT: seems some notebook OpenGL drivers on Windows might be ignoring the vsync flag...

http://en.sfml-dev.org/forums/index.php?topic=10429.msg71870#msg71870

EDIT2: a couple of other links about forcing vsync to be enabled on Windows

https://www.opengl.org/discussion_boards/showthread.php/146791-How-to-enable-force-VSYNC

http://stackoverflow.com/questions/589064/how-to-enable-vertical-sync-in-opengl

I'll have to see if I can figure that all out.

9
Window / [SOLVED] window.pollEvent() lagging when Joystick not plugged in
« on: October 06, 2015, 04:18:30 pm »
I'm going to mark this as solved since I already have a workaround. Although at the bottom of this post, I have a possible feature request. But first, here's the problem I encountered...

This is on Windows Vista with SFML-2.3.1.

There seems to be lag or "hiccups" in a smooth framerate when calling the window's pollEvent() without a Joystick/controller plugged in. I especially noticed this since I limit the framerate in my prototype game to 60fps - every second or so, there was a glitch or hiccup and by recording and printing out the frame periods I was able to verify this with most of the times being around 15 to 17 milliseconds but every so often a 30 or 40 ms period showing up.

Just through trial and error I noticed that this DOESN'T happen when I have an Xbox360 clone USB controller plugged in. Another way to "fix" the glitches was to remove the pollEvent() loop.

Anyway, after searching the forum a bit and consulting with a twitter pal, I found this thread:

http://en.sfml-dev.org/forums/index.php?topic=6079.0

That's obviously an old thread, but I guess some of it still applies.

TEST PROGRAM

//
// Simple example to demonstrate lag/hiccups in SFML when framerate is set to 60fps
// and window.pollEvent() is called.
//
// On my machine (Windows Vista 64bit) compiling with mingw  4.8.1 & SFML 2.3.1
// the lag or "hiccups" go away when I plug in a controller/joystick. Unplugging the
// controller again, the "hiccups" stay gone.
//
// Also commenting out the pollEvent() call "fixes" the problem. So maybe it's an
// interaction with a framerate limited to 60fps and polling for events when no
// controller is plugged in. Could just be my machine, too.
//   --> Core2 Duo T6500 CPU at 2.1 GHz
//       with Intel Graphics (but decent-ish "Entertainment" Notebook PC GPU)
//       surely I should be able to draw one quad at 60fps without lag.
//       Seems more like a bug somewhere with polling for controller Events???
//
// The hiccups can be seen in the flickering of the quad (that represents the frametime).
// This rectangle should be about 2*16 or 2*17 pixels long, where the 16 or 17 represent
// milliseconds between frames in the test program. However, the drawing is occasionally
// missed to to a lag introduced that takes the frametime up to around 30ms.
//
// Frame times can be verified by tapping the Return/Enter key to dump the last 100 frame
// times and whereas most are ~16ms, the occasional ~30ms time can be seen in the dump.
//

#include <SFML/Graphics.hpp>

#include <iostream>

int main()
{
  int Window_Width;
  int Window_Height;

  Window_Width = sf::VideoMode::getDesktopMode().width;
  Window_Height = sf::VideoMode::getDesktopMode().height;

  // Create a fullscreen window
  sf::RenderWindow renderWindow(sf::VideoMode(Window_Width, Window_Height),"FrameRate Test", sf::Style::None);

  renderWindow.setVerticalSyncEnabled(true);
  renderWindow.setFramerateLimit(60);

  // clock to measure time
  sf::Clock clock;
  sf::Int32 lastTime = 0;
  sf::Int32 thisTime = 0;
  sf::Int32 deltaTime;

  // check updates in ms
  int numChecks = 0;
  int i = 0;
  sf::Int32 check[100];

  // prime the timer/clock
  lastTime = clock.getElapsedTime().asMilliseconds();

  // draw a frame time quad
  sf::VertexArray ftquad(sf::Quads, 4);
  ftquad[0].position = sf::Vector2f(100,50);
  ftquad[1].position = sf::Vector2f(200,50);
  ftquad[2].position = sf::Vector2f(200,100);
  ftquad[3].position = sf::Vector2f(100,100);

  ftquad[0].color = sf::Color::Red;
  ftquad[1].color = sf::Color::Red;
  ftquad[2].color = sf::Color::Red;
  ftquad[3].color = sf::Color::Red;

  bool frametimes_dumped = false;

  // ********************************************************************************************************************
  // Start the game loop
  // ********************************************************************************************************************
  while (renderWindow.isOpen())
  {
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Escape)) {
          renderWindow.close();
    }

    // commenting out the pollEvent() call "fixes" the problem with lag/hiccups
    ///*
    sf::Event event;
    while (renderWindow.pollEvent(event)) {
        // DO NOTHING
    }
    //*/

    // -----------------------------------------------------------------
    // UPDATING
    // -----------------------------------------------------------------
    thisTime = clock.getElapsedTime().asMilliseconds();
    deltaTime = thisTime - lastTime;

    // record "frame time" from last frame to now
    check[numChecks] = deltaTime;
    numChecks++;
    if (numChecks >= 100) numChecks = 0;

    lastTime = thisTime;

    // draw a rectangle with length of twice the frame time
    ftquad[0].position = sf::Vector2f(100, 50);
    ftquad[1].position = sf::Vector2f(100 + deltaTime*2, 50);
    ftquad[2].position = sf::Vector2f(100 + deltaTime*2, 100);
    ftquad[3].position = sf::Vector2f(100, 100);

    // dump past 100 frame times when Return key is hit
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::Return) && !frametimes_dumped) {
        frametimes_dumped = true;
        for (i=numChecks; i < 100; i++) // dump older recorded frame times
                std::cout << "check" << std::dec << i << " : " << check[i] << "ms\n" ;
        for (i=0; i < numChecks; i++) // dump most recent recorded frame times
                std::cout << "check" << std::dec << i << " : " << check[i] << "ms\n" ;
    }

    // -----------------------------------------------------------------
    // DRAWING
    // -----------------------------------------------------------------
    renderWindow.clear(sf::Color::Black);
    renderWindow.draw(ftquad);
    renderWindow.display();

  }

  return EXIT_SUCCESS;
}

 

On my PC at least (and perhaps others), if you run the program without a controller plugged in, you'll see a red bar that shows the frame period, but occasionally it'll miss a frame and will just draw black. Commenting out the pollEvent() call/loop or plugging in a Controller alleviates the problem and it draws every frame.

It's possible you won't see this on a higher powered CPU, but I'm guessing it'll show up even there if you limit your framerate to 60fps and add the sort of complexity & number of entities you're drawing in an actual game.

WORKAROUND

I hacked together a somewhat similar workaround as the one mentioned in the older forum thread, but in this case, by adding a bool member to Win32/JoystickImpl.hpp

 
  // hacky new methods
  bool isfixConnected();
  void setfixConnected(bool flag);

  // hacky new private member
  bool m_fix_connected;

 

and Win32/JoystickImpl.cpp

  bool JoystickImpl::isfixConnected() {return m_fix_connected;}
  void JoystickImpl::setfixConnected(bool flag) {m_fix_connected = flag;}
 

and then changing Window/JoystickManager.cpp JoystickManager::update() to this

////////////////////////////////////////////////////////////
void JoystickManager::update()
{
    for (int i = 0; i < Joystick::Count; ++i)
    {
        Item& item = m_joysticks[i];

        if (item.state.connected)
        {
            // Get the current state of the joystick
            item.state = item.joystick.update();

            // Check if it's still connected
            if (!item.state.connected)
            {
                item.joystick.close();
                item.capabilities   = JoystickCaps();
                item.state          = JoystickState();
                item.identification = Joystick::Identification();
            }
        }
        else
        {
            // Check if the joystick was connected since last update
            // Hack - fix glitch when joystick is not connected
          if (!item.joystick.isfixConnected()) {
            // HACK - have it only check once...
            item.joystick.setfixConnected(true);

            if (JoystickImpl::isConnected(i))
            {
                if (item.joystick.open(i))
                {
                    item.capabilities   = item.joystick.getCapabilities();
                    item.state          = item.joystick.update();
                    item.identification = item.joystick.getIdentification();
                }
            }
          }
        }
    }
}

 

So it will only check once (when the game launches) whether a controller is plugged in. This fixes the "hiccups" in the frame rate.

FEATURE REQUEST?

I guess it might be a useful addition to add a flag to the Window & Joystick implementations to workaround this, so that the default is to check every time JoystickManager::update() is called, but allow the game dev to set a flag after creating the window so that it only checks once when the game starts.

That is until a definite solution is found.

Just putting this out there in case someone else runs into the same problem.

Pages: [1]