Respect the framelimit in all cases (Fixes #3531)

Affects loading screen, videos & modal dialogs. Also skips rendering if window is minimized.
pull/280/head
scrawl 7 years ago
parent dc53573de4
commit 8c6a8ca48d

@ -84,7 +84,6 @@ void OMW::Engine::frame(float frametime)
try try
{ {
mStartTick = mViewer->getStartTick(); mStartTick = mViewer->getStartTick();
mEnvironment.setFrameDuration (frametime);
// update input // update input
mEnvironment.getInputManager()->update(frametime, false); mEnvironment.getInputManager()->update(frametime, false);
@ -651,6 +650,8 @@ void OMW::Engine::go()
Settings::Manager::getString("screenshot format", "General"))); Settings::Manager::getString("screenshot format", "General")));
mViewer->addEventHandler(mScreenCaptureHandler); mViewer->addEventHandler(mScreenCaptureHandler);
mEnvironment.setFrameRateLimit(Settings::Manager::getFloat("framerate limit", "Video"));
// Create encoder // Create encoder
ToUTF8::Utf8Encoder encoder (mEncoding); ToUTF8::Utf8Encoder encoder (mEncoding);
mEncoder = &encoder; mEncoder = &encoder;
@ -684,7 +685,6 @@ void OMW::Engine::go()
// Start the main rendering loop // Start the main rendering loop
osg::Timer frameTimer; osg::Timer frameTimer;
double simulationTime = 0.0; double simulationTime = 0.0;
float framerateLimit = Settings::Manager::getFloat("framerate limit", "Video");
while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest()) while (!mViewer->done() && !mEnvironment.getStateManager()->hasQuitRequest())
{ {
double dt = frameTimer.time_s(); double dt = frameTimer.time_s();
@ -697,6 +697,8 @@ void OMW::Engine::go()
mViewer->advance(simulationTime); mViewer->advance(simulationTime);
mEnvironment.setFrameDuration(dt);
frame(dt); frame(dt);
if (!mEnvironment.getInputManager()->isWindowVisible()) if (!mEnvironment.getInputManager()->isWindowVisible())
@ -714,15 +716,7 @@ void OMW::Engine::go()
mViewer->renderingTraversals(); mViewer->renderingTraversals();
} }
if (framerateLimit > 0.f) mEnvironment.limitFrameRate(frameTimer.time_s());
{
double thisFrameTime = frameTimer.time_s();
double minFrameTime = 1.0 / framerateLimit;
if (thisFrameTime < minFrameTime)
{
OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime));
}
}
} }
// Save user settings // Save user settings

@ -2,6 +2,8 @@
#include <cassert> #include <cassert>
#include <OpenThreads/Thread>
#include "world.hpp" #include "world.hpp"
#include "scriptmanager.hpp" #include "scriptmanager.hpp"
#include "dialoguemanager.hpp" #include "dialoguemanager.hpp"
@ -17,7 +19,7 @@ MWBase::Environment *MWBase::Environment::sThis = 0;
MWBase::Environment::Environment() MWBase::Environment::Environment()
: mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0), : mWorld (0), mSoundManager (0), mScriptManager (0), mWindowManager (0),
mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mStateManager (0), mMechanicsManager (0), mDialogueManager (0), mJournal (0), mInputManager (0), mStateManager (0),
mFrameDuration (0) mFrameDuration (0), mFrameRateLimit(0.f)
{ {
assert (!sThis); assert (!sThis);
sThis = this; sThis = this;
@ -79,6 +81,29 @@ void MWBase::Environment::setFrameDuration (float duration)
mFrameDuration = duration; mFrameDuration = duration;
} }
void MWBase::Environment::setFrameRateLimit(float limit)
{
mFrameRateLimit = limit;
}
float MWBase::Environment::getFrameRateLimit() const
{
return mFrameRateLimit;
}
void MWBase::Environment::limitFrameRate(double dt) const
{
if (mFrameRateLimit > 0.f)
{
double thisFrameTime = dt;
double minFrameTime = 1.0 / static_cast<double>(mFrameRateLimit);
if (thisFrameTime < minFrameTime)
{
OpenThreads::Thread::microSleep(1000*1000*(minFrameTime-thisFrameTime));
}
}
}
MWBase::World *MWBase::Environment::getWorld() const MWBase::World *MWBase::Environment::getWorld() const
{ {
assert (mWorld); assert (mWorld);

@ -33,6 +33,7 @@ namespace MWBase
InputManager *mInputManager; InputManager *mInputManager;
StateManager *mStateManager; StateManager *mStateManager;
float mFrameDuration; float mFrameDuration;
float mFrameRateLimit;
Environment (const Environment&); Environment (const Environment&);
///< not implemented ///< not implemented
@ -67,6 +68,10 @@ namespace MWBase
void setFrameDuration (float duration); void setFrameDuration (float duration);
///< Set length of current frame in seconds. ///< Set length of current frame in seconds.
void setFrameRateLimit(float frameRateLimit);
float getFrameRateLimit() const;
void limitFrameRate(double dt) const;
World *getWorld() const; World *getWorld() const;
SoundManager *getSoundManager() const; SoundManager *getSoundManager() const;

@ -102,6 +102,15 @@ namespace MWGui
mBackgroundImage->setVisible(visible); mBackgroundImage->setVisible(visible);
} }
double LoadingScreen::getTargetFrameRate() const
{
double frameRateLimit = MWBase::Environment::get().getFrameRateLimit();
if (frameRateLimit > 0)
return std::min(frameRateLimit, mTargetFrameRate);
else
return mTargetFrameRate;
}
class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback class CopyFramebufferToTextureCallback : public osg::Camera::DrawCallback
{ {
public: public:
@ -141,7 +150,7 @@ namespace MWGui
if (mViewer->getIncrementalCompileOperation()) if (mViewer->getIncrementalCompileOperation())
{ {
mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100); mViewer->getIncrementalCompileOperation()->setMaximumNumOfObjectsToCompilePerFrame(100);
mViewer->getIncrementalCompileOperation()->setTargetFrameRate(mTargetFrameRate); mViewer->getIncrementalCompileOperation()->setTargetFrameRate(getTargetFrameRate());
} }
// Assign dummy bounding sphere callback to avoid the bounding sphere of the entire scene being recomputed after each frame of loading // Assign dummy bounding sphere callback to avoid the bounding sphere of the entire scene being recomputed after each frame of loading
@ -210,7 +219,7 @@ namespace MWGui
void LoadingScreen::setProgress (size_t value) void LoadingScreen::setProgress (size_t value)
{ {
// skip expensive update if there isn't enough visible progress // skip expensive update if there isn't enough visible progress
if (value - mProgress < mProgressBar->getScrollRange()/200.f) if (mProgressBar->getWidth() <= 0 || value - mProgress < mProgressBar->getScrollRange()/mProgressBar->getWidth())
return; return;
value = std::min(value, mProgressBar->getScrollRange()-1); value = std::min(value, mProgressBar->getScrollRange()-1);
mProgress = value; mProgress = value;
@ -231,7 +240,7 @@ namespace MWGui
bool LoadingScreen::needToDrawLoadingScreen() bool LoadingScreen::needToDrawLoadingScreen()
{ {
if ( mTimer.time_m() <= mLastRenderTime + (1.0/mTargetFrameRate) * 1000.0) if ( mTimer.time_m() <= mLastRenderTime + (1.0/getTargetFrameRate()) * 1000.0)
return false; return false;
// the minimal delay before a loading screen shows // the minimal delay before a loading screen shows

@ -43,6 +43,8 @@ namespace MWGui
virtual void setVisible(bool visible); virtual void setVisible(bool visible);
double getTargetFrameRate() const;
private: private:
void findSplashScreens(); void findSplashScreens();
bool needToDrawLoadingScreen(); bool needToDrawLoadingScreen();

@ -906,19 +906,30 @@ namespace MWGui
if (block) if (block)
{ {
osg::Timer frameTimer;
while (mMessageBoxManager->readPressedButton(false) == -1 while (mMessageBoxManager->readPressedButton(false) == -1
&& !MWBase::Environment::get().getStateManager()->hasQuitRequest()) && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
{ {
mMessageBoxManager->onFrame(0.f); double dt = frameTimer.time_s();
MWBase::Environment::get().getInputManager()->update(0, true, false); frameTimer.setStartTick();
mMessageBoxManager->onFrame(dt);
MWBase::Environment::get().getInputManager()->update(dt, true, false);
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
OpenThreads::Thread::microSleep(5000);
else
{
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
}
// at the time this function is called we are in the middle of a frame, // at the time this function is called we are in the middle of a frame,
// so out of order calls are necessary to get a correct frameNumber for the next frame. // so out of order calls are necessary to get a correct frameNumber for the next frame.
// refer to the advance() and frame() order in Engine::go() // refer to the advance() and frame() order in Engine::go()
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
MWBase::Environment::get().limitFrameRate(frameTimer.time_s());
} }
} }
} }
@ -1838,18 +1849,28 @@ namespace MWGui
if (mVideoWidget->hasAudioStream()) if (mVideoWidget->hasAudioStream())
MWBase::Environment::get().getSoundManager()->pauseSounds( MWBase::Environment::get().getSoundManager()->pauseSounds(
MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie)); MWBase::SoundManager::Play_TypeMask&(~MWBase::SoundManager::Play_TypeMovie));
osg::Timer frameTimer;
while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest()) while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
{ {
MWBase::Environment::get().getInputManager()->update(0, true, false); double dt = frameTimer.time_s();
frameTimer.setStartTick();
MWBase::Environment::get().getInputManager()->update(dt, true, false);
if (!MWBase::Environment::get().getInputManager()->isWindowVisible())
OpenThreads::Thread::microSleep(5000);
else
{
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
}
// at the time this function is called we are in the middle of a frame, // at the time this function is called we are in the middle of a frame,
// so out of order calls are necessary to get a correct frameNumber for the next frame. // so out of order calls are necessary to get a correct frameNumber for the next frame.
// refer to the advance() and frame() order in Engine::go() // refer to the advance() and frame() order in Engine::go()
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime()); mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
MWBase::Environment::get().limitFrameRate(frameTimer.time_s());
} }
mVideoWidget->stop(); mVideoWidget->stop();

Loading…
Cancel
Save