Quote:[Edited by - dc443 on September 17, 2008 7:06:40 PM]
Original post by bobmitch SOLVED!!! It's a quirk of nvidia's slightly experimental drivers I think. After puzzling over my code and how opengl works, I narrowed it down to either an SDL bug or a driver bug. The more I fiddled with various delays in my main loop, the more it seemed like a threading issue... but my code is running in a single thread right now. Solution: Disable threaded optimization in the advanced settings in the Nvidia control panel, it looks like it's set to Auto by default.
🔒 Locked
[SDL] Very strange event polling and vsync issue
Advertisement
Original Post
I am using SDL and OpenGL along with Box2D in my project. I would prefer to enable vsync, because it tends to reduce CPU load by at least 50%, while at the same time ensuring that there is never any graphical "tearing". What's not to like, right? Plus anyone can easily override the setting in their video drivers should they be bothered by the mouse lag that results (and thats an entirely different issue altogether). Well, there's this particularly strange issue that I'm getting. Whenever you move the mouse in the window WITHOUT ANY BUTTONS HELD DOWN, the SDL_PollEvent(SDL_Event*) and SDL_PumpEvents() functions often take over 13 milliseconds to execute. This is about the same time as an entire frame, so the animation becomes stuttery and in my case even the physics simulation is forced to slow down as a result. Okay, so I thought maybe this is just what it takes to figure out how far my mouse moved. This COULD be understandable since my mouse does refresh at 500Hz. But what's screwed up is, if I hold down a mouse button and THEN move it, there is now slowdown. Holding down of the four buttons (left click, middle click, right click, side button) works. I also know that SDL does in fact receieve all of the mouse motion data because if I am DRAGGING something along in my sim by holding down a button, it will run perfectly smoothly, then once I let go of the button, I have to stop moving the mouse or move it out of the screen to make the stuttering stop. Note that when I say stuttering, it's more like instead of each frame being displayed for exactly 1/60 second, it becomes something like one frame for 1/32, and another for 1/480... sure, average fps is 60, but visually you get 30fps. Fraps will display 60fps because it averages the value over several frames. You can try it for yourself and see if you can reproduce this issue: http://sourceforge.net/projects/box2dsandbox/ Get the 0.15 download. The stuttering effect is easiest to notice when you pick up the concave random-looking shape, and toss it somewhere. while its moving and spinning, move your mouse. If you look closely, you will also notice the entire simulation slow down as well (less so if you do not run 60Hz refresh, in fact all of the effects are reduced at higher refresh rates, but I can very easily notice it at 75Hz on my screen). This issue is not reproducible when vsync is off. Anyone got any ideas? EDIT: This appears to only affect Nvidia hardware on certain driver versions and I originally thought it was purely an SDL bug. You may be unable to reproduce it with my link above. SOLUTION:
while (SDL_PollEvent(&event)) { if( event.type == SDL_QUIT || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE )) quit = true; else if (event.type == SDL_MOUSEBUTTONDOWN) { ... } else if (event.type == SDL_MOUSEBUTTONUP) { ... } else if (event.type == SDL_MOUSEMOTION) { ... } else if (event.type == SDL_KEYDOWN) { ... } }When I did timings I started the timer right before the while loop, and put the timer.stop() right in the beginning of the loop, like this:
timer.startTimer(); while (SDL_PollEvent(&event)) { printf("%f ms\n",timer.stopTimer()*1000.); ...Also, if I comment out my entire event handling loop and use SDL_PumpEvents() instead, and use SDL_GetKeyState() and SDL_GetMouseState(), the exact same thing happens.
Okay, did some more testing and it definitely looks like this has something to do with VSync.
That's because when I have my refresh at 75Hz, polling events causes it to lag for 13.3 ms on average. 13.3333ms is exactly 1/75 second.
Similarly when I set my refresh to 60Hz, the lag increases to 16ms, and 1/60 s == 16.6667ms.
I still have no idea what might be causing this though. I mean, it works totally fine when a mouse button is pressed down. What is up with that!?!
That's because when I have my refresh at 75Hz, polling events causes it to lag for 13.3 ms on average. 13.3333ms is exactly 1/75 second.
Similarly when I set my refresh to 60Hz, the lag increases to 16ms, and 1/60 s == 16.6667ms.
I still have no idea what might be causing this though. I mean, it works totally fine when a mouse button is pressed down. What is up with that!?!
I'm on windows. XP 32 bit.
Inside debugDrawBody() are standard gl draw functions. I'm pretty sure there are no problems in there.
I've moved the drawing and swapping of buffers to different spots in the loop (before or after the event polling) to no avail.
Also what do you mean by rendering driver?
while (!quit) { //clear glClear(GL_COLOR_BUFFER_BIT); //drawing b2Body* body = world->GetBodyList(); while(body) { debugDrawBody(body, d); body = body->GetNext(); } //end drawing //swap buffers SDL_GL_SwapBuffers(); //SDL Event Handling while (SDL_PollEvent(&event)) { ... } ... // advance physics }Inside debugDrawBody() are standard gl draw functions. I'm pretty sure there are no problems in there.
I've moved the drawing and swapping of buffers to different spots in the loop (before or after the event polling) to no avail.
Also what do you mean by rendering driver?
I registered in this forums just for this question. I am having the same issue. I have a spinning pyramid and it will slow down when I move the mouse but when I move the mouse with some of the buttons pressed it will not happen. In my case I have a function that returns the time elapsed between frames and some times it gives me zero. I don't know how that's possible.
deltaTime some times is zero. I hope some one has a clue for this issue.
float getDeltaTime(void){ // return delta time return (this->deltaTime / 1000.0f);} // getDeltaTimedeltaTime some times is zero. I hope some one has a clue for this issue.
I think I solved the problem. At least in my case.
All I had to do was to get the time at the beginning of the frame then process all events then at the end of the loop get the time again and everything runs smooth again. I hope this helps you some how.
-r
All I had to do was to get the time at the beginning of the frame then process all events then at the end of the loop get the time again and everything runs smooth again. I hope this helps you some how.
// main loop for(;;) { // get time before frame this->beforeFrameTime = (float)SDL_GetTicks(); // handle events this->handleEvents(); // render stuff // ............. // get time after frame this->afterFrameTime = (float)SDL_GetTicks(); // time since last frame this->deltaTime = this->afterFrameTime - this->beforeFrameTime;}-r
As I understand it, what will happen is, normally the game loop finishes and calls Swap Buffers, which waits 16 or so miliseconds until swapping the buffers and allowing the loop to continue. With the SDL bug, sometimes the events functions will hog up 16 seconds, which means that once it reaches swap_buffers it will instantly swap the buffers and return. The result? One frame displayed for 1/30 second and one frame displayed for almost no time at all. I guess your timer isnt precise enough to catch the super short frame, which is probably going past in under 1 milisecond.
Well, I did more testing and I still get some frames where the delta time is zero but the animation looks very smooth. I had the same problem that you have. Specially when I had multi sampling on the animation would really slow down big time when you could really notice it. In my last run I go delta to be equal zero at frame, 0, 1, 2, 3704 and I was moving the mouse without any other button or key pressed. So maybe I have not solved the problem but at least things are better. :)
Move SDL_GL_SwapBuffers() to the end of the loop. You're basically waiting for the rendering to finish (due to VSync), *then* polling for events. Instead, you want to issue rendering commands, poll for events, do physics, and *then* swap the back buffers.
I actually have SDL_GL_SwapBuffers() as the last thing and still I get the same problem. They way that I went about it was to prevent deltaTime from being zero. Also having an internal fps limiter helps. If you have one then you then you can make all frames take the same time to render even if they were render quicker.
// regulate fpsif((this->maxFPS > 0) && ((SDL_GetTicks() - this->beforeFrameTime) < (1000.0 / this->maxFPS))){ // wait until the desired time has passed SDL_Delay((Uint32)((1000.0 / this->maxFPS) - (SDL_GetTicks() - this->beforeFrameTime)));}
Then only reason that I can think of that would make your animation slow down is when the delta time is zero so if you have something like:
Just because you request vsync it does not mean you are going to get it. So I'm kind of confused now. I thought the problem was that when you moved the mouse things would slow down but when you pressed the mouse buttons things would be normal. I had the same issue and I fixed by doing what I have described so far.
dy -= speed * dt;Just because you request vsync it does not mean you are going to get it. So I'm kind of confused now. I thought the problem was that when you moved the mouse things would slow down but when you pressed the mouse buttons things would be normal. I had the same issue and I fixed by doing what I have described so far.
Hi, I'm using SDL, opengl, and box2d as well and have never had this problem, but I can tell you how I do things and what I do differently from what you've told us.
I've turned v-sync off because if not, the screen updates sync with the monitor refresh rate, meaning that the rest of your game loop will never run faster than that limit. If you're concerned about CPU usage with v-sync off, try puting an SDL_Delay(1) call after you swap buffers. This yields the cpu to the OS, which mostly idles, and you'll see your task manager cpu percentage lower.
This is good for windowed mode, and saving battery on laptops.
As for the slowdown, are you doing anything that affects box2d in you mouse-motion event handling?
This is the order of calls I make:
time update
Update/Logic
Render
swap buffers
input task
Also, if you do turn v-sync off, you'll want to decouple the physics step from your framerate so the game doesn't slow down or speed up with the framerate.
I use Glenn Fiedler's timestep fix with the final touch and it works beautifully.
I hope that helps in some way.
I've turned v-sync off because if not, the screen updates sync with the monitor refresh rate, meaning that the rest of your game loop will never run faster than that limit. If you're concerned about CPU usage with v-sync off, try puting an SDL_Delay(1) call after you swap buffers. This yields the cpu to the OS, which mostly idles, and you'll see your task manager cpu percentage lower.
This is good for windowed mode, and saving battery on laptops.
As for the slowdown, are you doing anything that affects box2d in you mouse-motion event handling?
This is the order of calls I make:
time update
Update/Logic
Render
swap buffers
input task
Also, if you do turn v-sync off, you'll want to decouple the physics step from your framerate so the game doesn't slow down or speed up with the framerate.
I use Glenn Fiedler's timestep fix with the final touch and it works beautifully.
I hope that helps in some way.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement