SFML + fixed time step = lagging? - c++

I have a short question. I am learning SFML and I made few apps by using it. Someday I learned about using fixed time step while coding games and it would be great if it worked. BUT. Even though I am making simple project like square moving from left to right side of the window - it is lagging! What could be a cause of this problem? This is my code:
#include <SFML/Graphics.hpp>
int main()
{
sf::RenderWindow window(sf::VideoMode(800, 600), "Window");
window.setVerticalSyncEnabled(true);
sf::Event event;
sf::Clock clock;
sf::Time accumulator = sf::Time::Zero;
const sf::Time timePerFrame = sf::seconds(1.f / 60.f);
sf::RectangleShape square;
square.setSize(sf::Vector2f(32, 32));
square.setOrigin(16, 16);
square.setPosition(400, 300);
square.setFillColor(sf::Color::Red);
int direction = 1;
int speed = 300;
while(window.isOpen())
{
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed)
{
window.close();
}
}
while(accumulator >= timePerFrame)
{
if(square.getPosition().x <= 16 || square.getPosition().x >= 784) direction *= (-1);
square.move(sf::Vector2f(speed * direction * timePerFrame.asSeconds(), 0));
accumulator -= timePerFrame;
}
accumulator += clock.restart();
window.clear(sf::Color::Black);
window.draw(square);
window.display();
}
return 0;
}
As you can see I know about vertical synchronization, but it doesnt help so much. Is my fixed time step loop wrong? Any help is appreciated!

Have you tried not enabling vertical sync? Both vertical sync and the timestep you have implemented may interfere with each other by both trying to control the framerate at the same time. On the SFML tutorial page for windows they state:
"Never use both setVerticalSyncEnabled and setFramerateLimit at the same time! They would badly mix and make things worse."
As you can see here from the source code for SFML:
void Window::setFramerateLimit(unsigned int limit)
{
if (limit > 0)
m_frameTimeLimit = seconds(1.f / limit);
else
m_frameTimeLimit = Time::Zero;
}
void Window::display()
{
// Display the backbuffer on screen
if (setActive())
m_context->display();
// Limit the framerate if needed
if (m_frameTimeLimit != Time::Zero)
{
sleep(m_frameTimeLimit - m_clock.getElapsedTime());
m_clock.restart();
}
}
SFML's setFramerateLimit function is implemented in much the same way as your timestep, and thus I don't believe the situation would be any different here.
Upon testing your code on my machine I did see a slight lag on the square, however, disabling vertical sync fixed the issue.
Edit: It turns out this issue is more complex than I originally thought (and I also overlooked the obvious need for vsync if there's tearing). After days of research and messing around with the code, I've learned of a few things that fix the issue:
Disabling vsync (though of course we already know this)
Recording the program with Fraps
Calling glFinish() after window.display()
Creating a window in either fullscreen, or borderless (with sf::Style::None) at the same size as the desktop
Disabling Windows Aero theme (though of course this only applies to Windows)
All of those except the first will fix it even when vsync is enabled. The main problem here seems to be that vsync doesn't work correctly in windowed mode, apparently it's a limitation due to how the program has to share screen space with other programs that don't necessarily have vsync enabled.
So my suggestion:
Use glFinish() after every display() call if using windowed mode, although this has a penalty, it halts the CPU and synchronizes it with the GPU and monitor when it could be processing asynchronously and uninterrupted, but if your program isn't particularly CPU intensive then this shouldn't be much of an issue. In SFML you can include "SFML/OpenGL.hpp" to get access to this function. Although if you are using Windows (Vista and 7 I believe, I don't know how 8 or 10 handles things though) then while using an Aero theme vsync is apparently automatically enabled and you may not have tearing to begin with. What operating system are you using?
Use fullscreen and just accept that there will be stuttering in windowed mode. It may not even be noticeable in an actual game or other graphical application, as opposed to a rigid high contrast square moving continuously back and forth on a blank background. I know that in the game I am working on right now I have the same problem, but I hardly ever noticed it.
Read up on the issue and see if you can find a true fix. Admittedly using glFinish is somewhat of a kludge, and dealing with stuttering or tearing in windowed mode may not be acceptable. I'm not entirely sure how glFinish manages to eliminate the stutter, and it's usually never recommended to call that function anyway.
Some further reading:
https://superuser.com/questions/558007/how-does-windows-aero-prevent-screen-tearing
http://www.cplusplus.com/forum/general/108295/
http://forums.nesdev.com/viewtopic.php?f=3&t=9262#p98808 (especially
this post by rainwarrior)
https://www.opengl.org/wiki/Swap_Interval (what SFML calls internally
to enable vsync)
http://www.gamedev.net/topic/381574-sdl-no-vsync-in-windowed-mode/
http://larian.com/forums/ubbthreads.php?ubb=showflat&Number=482323
http://dev.dota2.com/archive/index.php/t-11450.html

Related

Am I using double buffering?

I am building a Windows MFC application. During some animations where objects collide at high speeds, my physics engine behaves unpredictably. I believe it has something to do with me dropping frames somehow. I was told that I'm not using double buffering. I thought I was, but I am still fairly new to this. Here is how I draw to the screen in OnPaint:
#include "pch.h"
#include "framework.h"
#include "ChildView.h"
#include "DoubleBufferDC.h"
void CChildView::OnPaint()
{
CPaintDC paintDC(this); // device context for painting
CDoubleBufferDC dc(&paintDC); // device context for painting
Graphics graphics(dc.m_hDC); // Create GDI+ graphics context
mGame.OnDraw(&graphics);
if (mFirstDraw)
{
mFirstDraw = false;
SetTimer(1, FrameDuration, nullptr);
/*
* Initialize the elapsed time system
*/
LARGE_INTEGER time, freq;
QueryPerformanceCounter(&time);
QueryPerformanceFrequency(&freq);
mLastTime = time.QuadPart;
mTimeFreq = double(freq.QuadPart);
}
/*
* Compute the elapsed time since the last draw
*/
LARGE_INTEGER time;
QueryPerformanceCounter(&time);
long long diff = time.QuadPart - mLastTime;
double elapsed = double(diff) / mTimeFreq;
mLastTime = time.QuadPart;
mGame.Update(elapsed);
}
void CChildView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
RedrawWindow(NULL, NULL, RDW_UPDATENOW);
Invalidate();
CWnd::OnTimer(nIDEvent);
}
When I create the Graphics object from the CDoubleBufferDC object, is this not creating a back buffer? I then pass this Graphics object to OnDraw where it is drawn on. If it is creating a back buffer, I'm confused about where the front buffer is created and when it is drawn on the screen.
Here are my current thoughts on how I think this works:
The CPaintDC object is the front buffer
The CDoubleBufferDC object is the back buffer
A graphics object is created from the CDoubleBufferDC object which I draw the current state of the game on
If this is the case, when is the front buffer ever replaced with the new buffer created in the back? Can someone help me understand, and use double buffering if I'm not already?
To answer your actual question, what is probably happening is that your CDoubleBufferDC() class has a destructor that swaps out the DC's - this is a common idiom (IIRC in 'modern' MFC versions CMemDC does that too). So yes I think you are using double buffering here, even if accidentally. You can do the drawing in GDI(+) for simple games, if this whole thing is a learning exercise, this way is much easier to understand than using DirectX.
However, you do need to decouple your collision detection from your drawing routines, so that any dropped frames don't mess up your timing (that is, if you're things so complex that they take that much time - in which case, you probably shouldn't be using GDI...). In other words, if your collision detection assumes that each OnDraw() call completes in less than 1/framerate seconds but that doesn't always happen, you'll run into problems at some point. There are many articles online about how to structure your game loop; I don't have enough information to link you to a specific one. Also it won't be easy to find one using the technology you're using, in 2020... But I do think that using a simple OnPaint()/GDI one is great for learning, as it will hide much of the complexity you need for more modern approaches.

Trouble with vsync using glut in OpenGL

I'm struggling desperately to get Vsync to work in my OpenGL application. Here's the vital stats:
I'm using Windows, coding in C++ OpenGL and I'm using FreeGLUT for my OpenGL context (double buffering). I'm aware that for the swap buffer to wait for vertical sync in Windows you are required to call wglSwapIntervalEXT().
My code does call this (as you'll see below), yet I am still getting vertical tearing. The only way I've managed to stop it is by calling glFinish() which of course has a significant performance penalty associated with it.
The relevant parts of my main() function look like this:
//Initiating glut window
glutInit(&argc, argv);
glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize (initial_window_width, initial_window_height);
glutInitWindowPosition (100, 100);
int glut_window_hWnd = glutCreateWindow(window_title.c_str());
//Setting up swap intervals
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT = NULL;
PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = NULL;
if (WGLExtensionSupported("WGL_EXT_swap_control"))
{
// Extension is supported, init pointers.
wglSwapIntervalEXT = PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
// this is another function from WGL_EXT_swap_control extension
wglGetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC)wglGetProcAddress("wglGetSwapIntervalEXT");
}
wglSwapIntervalEXT (1)
init ();
glutMainLoop(); ///Starting the glut loop
return(0);
I should point out that the return from the wglInitSwapControlARB function is true, so the extension is supported.
Ok - between the great help I've received here, and my own hours of research and messing around with it I've discovered a few things, including a solution that works for me (in case others come across this problem).
Firstly, I was using freeGLUT, I converted my code to GLFW and the result was the same, so this was NOT an API issue, don't waste your time like I did!
In my program at least, using wglSwapIntervalEXT(1) DOES NOT stop vertical tearing, and this was what led to it being such a headache to solve.
With my NVIDIA driver set to VSYNC = ON I was still getting tearing (because this is equivalent to SwapInterval(1) which doesn't help) - but it was set correctly, the driver was doing what it should have been I just didn't know it because I was still getting tearing.
So I set my NVIDIA driver to VSYNC = 'Application preference' and used wglSwapIntervalEXT(60) instead of 1 which I had always been using, and found that this was actually working because it was giving me a refresh rate of about 1Hz.
I don't know why wglSwapIntervalEXT(1) doesn't Vsync my screen, but wglSwapIntervalEXT(2) has the desired effect, though obviously I'm now rendering every other frame which is inefficient.
I found that with VSYNC disabled glFinish DOES NOT help with tearing, but with it enabled it does (If anyone can explain why that would be great).
So in summary, with wglSwapIntervalEXT(1) set and glFinish() enabled I no longer have tearing, but I don't understand still why.
Here's some performance stats in my app (deliberately loaded to have FPS's below 60):
wglSwapIntervalEXT(0) = Tearing = 58 FPS
wglSwapIntervalEXT(1) = Tearing = 58 FPS
wglSwapIntervalEXT(2) = No tearing = 30 FPS
wglSwapIntervalEXT(1) + glFinish = No Tearing = 52 FPS
I hope this helps someone in the future. Thanks for all your help.
i am also having problem with vsync and freeglut.
previously i used glut, and i was able to selectivly enable vsync for multiple GLUT-windows.
Now with freeglut, it seems like that the wglSwapIntervalEXT() has no effect.
What has effect is the global vsync option in the NVIDIA control panel. If I enable the vsync there, i have vsync in both of my freeglut windows, and if i disable i dont have. It does not matter what i set specificly for my application (in the nvidia control panel).
Also this confirms what i observe:
if(wglSwapIntervalEXT(0))
printf("VSYNC set\n");
int swap=wglGetSwapIntervalEXT();
printf("Control window vsync: %i\n",swap);
the value of swap is always the value that is set in the NVIDIA control panel.
Does not matter what is want to set with wglSwapIntervalEXT().
Otherwise here you can read what the GLFinish() is good for:
http://www.opengl.org/wiki/Swap_Interval
I use it because i need to know when my monitor is updated, so i can synchronously execute tasks after that (capture with a camera something).
As described in this question here, no "true" VSync exists. Using GLFinish is the correct approach. This will cause your Card to finish processing everything it has been sent before continuing and rendering the next frame.
You should keep track of your FPS and the time to render a frame, you might find GLFinish is simply exposing another bottleneck in your code.

SFML flickering renderwindow?

I'm hoping someone can help me out, I'm using SFML 2.1 and when I draw my renderWindow it just keeps flickering, now I know SFML uses two buffers so i'm sure one is not getting drawn at all but I can't understand why.
Here is my loop
while(!quit)
{
rs.Canvas.pollEvent(gameEvent);
colour += 1;
rs.Update(colour);
if(gameEvent.type == sf::Event::Closed)
quit = true;
rs.Canvas.clear( sf::Color(colour,0,0) );
rs.Canvas.draw( sprite );
rs.Canvas.display();
if(colour >= 300)
quit = true;
}
the rs.Canvas has these set
Canvas.setVerticalSyncEnabled(true);
Canvas.setFramerateLimit(60);
Can anyone see why my renderWindow would flicker?
From the SFML 2.0 tutorial, under the section Controlling the framerate:
Never use both setVerticalSyncEnabled and setFramerateLimit at the same time! They would badly mix and make things worse.
http://www.sfml-dev.org/tutorials/2.0/window-window.php#controlling-the-framerate
In the comments of your post, you state that you were calling clear twice on the window. This would effectively treat your window as if it were single buffered. I understand that the effect of this could create some screen tearing, but on my end I am not getting a glaring flicker effect. Make sure to remove your a call to either setting the framerate or to using the vertical sync, just to be sure.
Basically I was calling
rs.Canvas.clear
twice. I removed the second call and everything then worked fine

How to sync page-flips with vertical retrace in a windowed SDL application?

I'm currently writing a game of immense sophistication and cunning, that will fill you with awe and won- oh, OK, it's the 15 puzzle, and I'm just familiarising myself with SDL.
I'm running in windowed mode, and using SDL_Flip as the general-case page update, since it maps automatically to an SDL_UpdateRect of the full window in windowed mode. Not the optimum approach, but given that this is just the 15 puzzle...
Anyway, the tile moves are happening at ludicrous speed. IOW, SDL_Flip in windowed mode doesn't include any synchronisation with vertical retraces. I'm working in Windows XP ATM, but I assume this is correct behaviour for SDL and will occur on other platforms too.
Switching to using SDL_UpdateRect obviously won't change anything. Presumably, I need to implement the delay logic in my own code. But a simple clock-based timer could result in updates occuring when the window is half-drawn, causing visible distortions (I forget the technical name).
EDIT This problem is known as "tearing".
So - in a windowed mode game in SDL, how do I synchronise my page-flips with the vertical retrace?
EDIT I have seen several claims, while searching for a solution, that it is impossible to synchronise page-flips to the vertical retrace in a windowed application. On Windows, at least, this is simply false - I have written games (by which I mean things on a similar level to the 15-puzzle) that do this. I once wasted some time playing with Dark Basic and the Dark GDK - both DirectX-based and both syncronising page-flips to the vertical retrace in windowed mode.
Major Edit
It turns out I should have spent more time looking before asking. From the SDL FAQ...
http://sdl.beuc.net/sdl.wiki/FAQ_Double_Buffering_is_Tearing
That seems to imply quite strongly that synchronising with the vertical retrace isn't supported in SDL windowed-mode apps.
But...
The basic technique is possible on Windows, and I'm beginning the think SDL does it, in a sense. Just not quite certain yet.
On Windows, I said before, synchronising page-flips to vertical syncs in Windowed mode has been possible all the way back to the 16-bit days using WinG. It turns out that that's not exactly wrong, but misleading. I dug out some old source code using WinG, and there was a timer triggering the page-blits. WinG will run at ludicrous speed, just as I was surprised by SDL doing - the blit-to-screen page-flip operations don't wait for a vertical retrace.
On further investigation - when you do a blit to the screen in WinG, the blit is queued for later and the call exits. The blit is executed at the next vertical retrace, so hopefully no tearing. If you do further blits to the screen (dirty rectangles) before that retrace, they are combined. If you do loads of full-screen blits before the vertical retrace, you are rendering frames that are never displayed.
This blit-to-screen in WinG is obviously similar to the SDL_UpdateRect. SDL_UpdateRects is just an optimised way to manually combine some dirty rectangles (and be sure, perhaps, they are applied to the same frame). So maybe (on platforms where vertical retrace stuff is possible) it is being done in SDL, similarly to in WinG - no waiting, but no tearing either.
Well, I tested using a timer to trigger the frame updates, and the result (on Windows XP) is uncertain. I could get very slight and occasional tearing on my ancient laptop, but that may be no fault of SDLs - it could be that the "raster" is outrunning the blit. This is probably my fault for using SDL_Flip instead of a direct call to SDL_UpdateRect with a minimal dirty rectangle - though I was trying to get tearing in this case, to see if I could.
So I'm still uncertain, but it may be that windowed-mode SDL is as immune to tearing as it can be on those platforms that allow it. Results don't seem as bad as I imagined, even on my ancient laptop.
But - can anyone offer a definitive answer?
You can use the framerate control of SDL_gfx.
Looking at the docs of library, the flow of your application will be like this:
// initialization code
FPSManager *fpsManager;
SDL_initFramerate(fpsManager);
SDL_setFramerate(fpsManager, 60 /* desired FPS */);
// in the render loop
SDL_framerateDelay(fpsManager);
Also, you may look at the source code to create your own framerate control.

How to redraw the picture while moving windows in openGL?

I have drawn a picture with openGL on my windows. Now whenever I hold the mouse button on the windows and move it, my picture always got distorted. I don't know what function in openGL that can help me redraw the picture while the windows is moved. Anybody could help?
I tried this but seems not work:
void myDisplay()
{
.....
}
void reshape(int x, int y)
{
glutPostRedisplay();
}
int main()
{
.....
glutDisplayFunc(myDisplay);
glutReshapeFunc(reshape);
}
The first (and usually only) necessary step is to to quit using glut. glut is oriented primarily toward producing a static display, so it attempts to accumulate changes and then redraw only when the state has "stabilized" again, such as when you're done resizing the window. That made sense at one time, but mostly doesn't anymore.
Given that it's been around 10 years since glut was last updated, out of date design goals are hardly a surprise. That doesn't change the fact that it's carefully written to prevent what you want from happening. If you wanted to, you could probably rewrite it to fit your expectations better, but it'll almost certainly be quite a bit simpler to use something else that's designed to do what you want (or at least something closer to what you want).
Add glutIdleFunc function
int main()
{
.....
glutDisplayFunc(myDisplay);
glutIdleFunc(myDisplay);
glutReshapeFunc(reshape);
}
Solution that worked for me was to skip the execution of InvalidateRect/RedrawWindow functions after calling MoveWindow on WM_MOUSEMOVE (I'm not using glut). Because usually it makes sense to execute InvalidateRect(wnd,0,0) after all mouse/keyboard events, but apprently calling it after MoveWindow causes the window contents to "stay behind" dragging.