Flickering when restricting fps

This topic is 4452 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

Recommended Posts

I'm having problems properly restricting the fps of my engine. I mean, I can restrict the fps, but if I do it properly, it won't draw properly.
/**
* Set the fps to not go over a certain value.
* \param f The value for the fps to not to exceed
*/
void CSceneGraph::setFPS(float f)
{
m_minTimeBetweenFrames = 1.0f / f;
m_time = 0.0f;
}

/**
* Render all objects in the scene graph.
*/
void CSceneGraph::render()
{
util::list<ISceneGraphNode*>::iterator i = m_nodeList.begin();

//while( (m_time += m_hiResTimer.getElapsedSeconds()) < m_minTimeBetweenFrames );

if( (m_time += m_hiResTimer.getElapsedSeconds()) < m_minTimeBetweenFrames )
return;

for( ; i != m_nodeList.end(); i++){
// use these three to get the constant frame rate going
(*i)->preRender( m_time );
(*i)->render();
(*i)->postRender( m_time );
}

// reset time to 0.0f because we have just drawn a frame
m_time = 0.0f;
}


The way it is now, it should return to the main loop so whatever else that should be done can be done. ie - non graphics related things. But, it flickers insanely, and I don't get the fps restriction. And, if I use the while loop instead, it works perfectly, without any flickering, and the restriction is perfect. This is the main loop:
// temp vars for counting the FPS
unsigned int lastFPS = 0;
char str[1024];
while( engine->run() ){

driver->beginScene();

// reset the world/modelview matrix to the identity matrix
driver->resetMatrix(video::WORLD_MATRIX);

// use input to rotate

engine->getSceneManager()->render();

driver->endScene();

// count the FPS
unsigned int temp = driver->getFPSCounter().getFPS();

if( temp != lastFPS ){
lastFPS = temp;
sprintf(str, "Current FPS: %d", temp);
engine->setWindowCaption(str);
}
}


I'm using openGL, and nothing actually gets passed to openGL (transformation and rendering) until the scene manager renders the scene graph. But, in 'driver->endScene()', I am calling the windows function 'SwapBuffers'. Could that be causing this? Because if I haven't actually drawn anything, just a blank buffer will be swapped to the front, right? If you think this is my problem, is there a way to find out if a change has been made to the back buffer?

Share on other sites
You should swap only at the end. Maybe you swap too early.

Share on other sites
I do swap only at the end.

/** * Does OGL housekeeping for the end of rendering a frame. * Flushes the pipeline, swap buffers, counts fps. */void COpenGLDriver::endScene(){	glFlush();			// flush the pipeline	SwapBuffers(hDC);	// render the scene to the window	// do the FPS calculating, etc	IVideoDriver::endScene();}

This is only called once every iteration of the loop.

Share on other sites
Check your timer routines. You swap uncontrolled. The cause of flickering is in my opinion that you must integrate your swap into your frame limiter, in other words check for delta time. if it is bigger as 1.0 / desired fps, then swap

Share on other sites
One is how the swap is done. You can provide a hint to swap or copy, but on my machine it always copies. If you actually swap, i.e. back becomes front and front becomes back, then you would need the same image in both to keep swapping. If it's copy you just need the right image in the back buffer. The easiest way to check is just do it manually. During setup clear to one color, swap, then clear to another. Then in response to a kep press swap buffers. No drawing, no clearing, just swap. If the screen stays one color it's copying, if it changes it's swapping.

If it's copying then make sure you aren't clearing the buffer between swaps while not always rendering. Otherwise the image may only be displayed a small fraction of the fixed frame time. The swap is going to take 1ms or so with vertical sync turned off. It makes a nice, easy way to idle the CPU while you wait. If you don't care about burning CPU then you shouldn't swap without changing the image.