Fix FPS counter

This commit is contained in:
Brad Davis 2016-04-08 20:14:30 -07:00
parent b87e8220c4
commit df8ad57185
15 changed files with 166 additions and 137 deletions

View file

@ -48,12 +48,22 @@ Item {
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Render Rate: " + root.renderrate
text: "Render Rate: " + root.renderrate.toFixed(2);
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Present Rate: " + root.presentrate
text: "Present Rate: " + root.presentrate.toFixed(2);
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Present New Rate: " + root.presentnewrate.toFixed(2);
}
Text {
color: root.fontColor;
font.pixelSize: root.fontSize
text: "Present Drop Rate: " + root.presentdroprate.toFixed(2);
}
Text {
color: root.fontColor;

View file

@ -511,8 +511,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
_sessionRunTimer(startupTimer),
_previousSessionCrashed(setupEssentials(argc, argv)),
_undoStackScriptingInterface(&_undoStack),
_frameCount(0),
_fps(60.0f),
_physicsEngine(new PhysicsEngine(Vectors::ZERO)),
_entityClipboardRenderer(false, this, this),
_entityClipboard(new EntityTree()),
@ -1332,7 +1330,7 @@ void Application::initializeGL() {
_idleLoopStdev.reset();
// update before the first render
update(1.0f / _fps);
update(0);
InfoView::show(INFO_HELP_PATH, true);
}
@ -1463,7 +1461,6 @@ void Application::initializeUi() {
}
void Application::paintGL() {
updateHeartbeat();
// Some plugins process message events, potentially leading to
@ -1481,24 +1478,7 @@ void Application::paintGL() {
return;
}
_frameCount++;
// update fps moving average
uint64_t now = usecTimestampNow();
static uint64_t lastPaintBegin{ now };
uint64_t diff = now - lastPaintBegin;
float instantaneousFps = 0.0f;
if (diff != 0) {
instantaneousFps = (float)USECS_PER_SECOND / (float)diff;
_framesPerSecond.updateAverage(_lastInstantaneousFps);
}
lastPaintBegin = now;
// update fps once a second
if (now - _lastFramesPerSecondUpdate > USECS_PER_SECOND) {
_fps = _framesPerSecond.getAverage();
_lastFramesPerSecondUpdate = now;
}
_frameCounter.increment();
PROFILE_RANGE_EX(__FUNCTION__, 0xff0000ff, (uint64_t)_frameCount);
PerformanceTimer perfTimer("paintGL");
@ -1655,7 +1635,7 @@ void Application::paintGL() {
}
// Update camera position
if (!isHMDMode()) {
_myCamera.update(1.0f / _fps);
_myCamera.update(1.0f / _frameCounter.rate());
}
}
@ -1752,8 +1732,6 @@ void Application::paintGL() {
batch.resetStages();
});
}
_lastInstantaneousFps = instantaneousFps;
}
void Application::runTests() {
@ -2625,32 +2603,19 @@ bool Application::acceptSnapshot(const QString& urlString) {
static uint32_t _renderedFrameIndex { INVALID_FRAME };
void Application::idle(uint64_t now) {
// NOTICE NOTICE NOTICE NOTICE
// Do not insert new code between here and the PROFILE_RANGE declaration
// unless you know exactly what you're doing. This idle function can be
// called thousands per second or more, so any additional work that's done
// here will have a serious impact on CPU usage. Only add code after all
// the thottling logic, i.e. after PROFILE_RANGE
// NOTICE NOTICE NOTICE NOTICE
updateHeartbeat();
if (_aboutToQuit || _inPaint) {
return; // bail early, nothing to do here.
}
// These tasks need to be done on our first idle, because we don't want the showing of
// overlay subwindows to do a showDesktop() until after the first time through
static bool firstIdle = true;
if (firstIdle) {
firstIdle = false;
auto offscreenUi = DependencyManager::get<OffscreenUi>();
connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
_overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays));
}
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
_keyboardMouseDevice->pluginFocusOutEvent();
_keyboardDeviceHasFocus = false;
} else if (offscreenUi && offscreenUi->getWindow()->activeFocusItem() == offscreenUi->getRootItem()) {
_keyboardDeviceHasFocus = true;
}
auto displayPlugin = getActiveDisplayPlugin();
// depending on whether we're throttling or not.
// Once rendering is off on another thread we should be able to have Application::idle run at start(0) in
@ -2684,8 +2649,36 @@ void Application::idle(uint64_t now) {
return;
}
// NOTICE NOTICE NOTICE NOTICE
// do NOT add new code above this line unless you want it to be executed potentially
// thousands of times per second
// NOTICE NOTICE NOTICE NOTICE
PROFILE_RANGE(__FUNCTION__);
// These tasks need to be done on our first idle, because we don't want the showing of
// overlay subwindows to do a showDesktop() until after the first time through
static bool firstIdle = true;
if (firstIdle) {
firstIdle = false;
auto offscreenUi = DependencyManager::get<OffscreenUi>();
connect(offscreenUi.data(), &OffscreenUi::showDesktop, this, &Application::showDesktop);
_overlayConductor.setEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Overlays));
}
// If the offscreen Ui has something active that is NOT the root, then assume it has keyboard focus.
auto offscreenUi = DependencyManager::get<OffscreenUi>();
if (_keyboardDeviceHasFocus && offscreenUi && offscreenUi->getWindow()->activeFocusItem() != offscreenUi->getRootItem()) {
_keyboardMouseDevice->pluginFocusOutEvent();
_keyboardDeviceHasFocus = false;
} else if (offscreenUi && offscreenUi->getWindow()->activeFocusItem() == offscreenUi->getRootItem()) {
_keyboardDeviceHasFocus = true;
}
// We're going to execute idle processing, so restart the last idle timer
_lastTimeUpdated.start();
@ -2694,14 +2687,7 @@ void Application::idle(uint64_t now) {
Stats::getInstance()->updateStats();
AvatarInputs::getInstance()->update();
{
static uint64_t lastIdleStart{ now };
uint64_t idleStartToStartDuration = now - lastIdleStart;
if (idleStartToStartDuration != 0) {
_simsPerSecond.updateAverage((float)USECS_PER_SECOND / (float)idleStartToStartDuration);
}
lastIdleStart = now;
}
_simCounter.increment();
PerformanceTimer perfTimer("idle");
// Drop focus from _keyboardFocusedItem if no keyboard messages for 30 seconds
@ -2757,30 +2743,6 @@ void Application::idle(uint64_t now) {
emit checkBackgroundDownloads();
}
float Application::getAverageSimsPerSecond() {
uint64_t now = usecTimestampNow();
if (now - _lastSimsPerSecondUpdate > USECS_PER_SECOND) {
_simsPerSecondReport = _simsPerSecond.getAverage();
_lastSimsPerSecondUpdate = now;
}
return _simsPerSecondReport;
}
void Application::setAvatarSimrateSample(float sample) {
_avatarSimsPerSecond.updateAverage(sample);
}
float Application::getAvatarSimrate() {
uint64_t now = usecTimestampNow();
if (now - _lastAvatarSimsPerSecondUpdate > USECS_PER_SECOND) {
_avatarSimsPerSecondReport = _avatarSimsPerSecond.getAverage();
_lastAvatarSimsPerSecondUpdate = now;
}
return _avatarSimsPerSecondReport;
}
void Application::setLowVelocityFilter(bool lowVelocityFilter) {
controller::InputDevice::setLowVelocityFilter(lowVelocityFilter);
}
@ -3051,7 +3013,7 @@ void Application::updateLOD() const {
PerformanceTimer perfTimer("LOD");
// adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode
if (!isThrottleRendering()) {
DependencyManager::get<LODManager>()->autoAdjustLOD(_fps);
DependencyManager::get<LODManager>()->autoAdjustLOD(_frameCounter.rate());
} else {
DependencyManager::get<LODManager>()->resetLODAdjust();
}
@ -3482,8 +3444,7 @@ void Application::update(float deltaTime) {
// AvatarManager update
{
PerformanceTimer perfTimer("AvatarManger");
qApp->setAvatarSimrateSample(1.0f / deltaTime);
_avatarSimCounter.increment();
{
PROFILE_RANGE_EX("OtherAvatars", 0xffff00ff, (uint64_t)getActiveDisplayPlugin()->presentCount());
@ -3805,7 +3766,8 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
bool Application::isHMDMode() const {
return getActiveDisplayPlugin()->isHmd();
}
float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); }
float Application::getTargetFrameRate() const { return getActiveDisplayPlugin()->getTargetFrameRate(); }
QRect Application::getDesirableApplicationGeometry() const {
QRect applicationGeometry = getWindow()->geometry();

View file

@ -39,6 +39,7 @@
#include <StDev.h>
#include <ViewFrustum.h>
#include <AbstractUriHandler.h>
#include <shared/RateCounter.h>
#include "avatar/MyAvatar.h"
#include "Bookmarks.h"
@ -155,10 +156,9 @@ public:
bool isForeground() const { return _isForeground; }
uint32_t getFrameCount() const { return _frameCount; }
float getFps() const { return _fps; }
float getTargetFrameRate(); // frames/second
float getLastInstanteousFps() const { return _lastInstantaneousFps; }
size_t getFrameCount() const { return _frameCount; }
float getFps() const { return _frameCounter.rate(); }
float getTargetFrameRate() const; // frames/second
float getFieldOfView() { return _fieldOfView.get(); }
void setFieldOfView(float fov);
@ -216,10 +216,9 @@ public:
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
void updateMyAvatarLookAtPosition();
float getAvatarSimrate();
void setAvatarSimrateSample(float sample);
float getAverageSimsPerSecond();
float getAvatarSimrate() const { return _avatarSimCounter.rate(); }
float getAverageSimsPerSecond() const { return _simCounter.rate(); }
signals:
void svoImportRequested(const QString& url);
@ -396,12 +395,15 @@ private:
QUndoStack _undoStack;
UndoStackScriptingInterface _undoStackScriptingInterface;
uint32_t _frameCount { 0 };
// Frame Rate Measurement
int _frameCount;
float _fps;
RateCounter<> _frameCounter;
RateCounter<> _avatarSimCounter;
RateCounter<> _simCounter;
QElapsedTimer _timerStart;
QElapsedTimer _lastTimeUpdated;
float _lastInstantaneousFps { 0.0f };
ShapeManager _shapeManager;
PhysicalEntitySimulation _entitySimulation;
@ -488,12 +490,6 @@ private:
EntityItemID _keyboardFocusedItem;
quint64 _lastAcceptedKeyPress = 0;
SimpleMovingAverage _framesPerSecond{10};
quint64 _lastFramesPerSecondUpdate = 0;
SimpleMovingAverage _simsPerSecond{10};
int _simsPerSecondReport = 0;
quint64 _lastSimsPerSecondUpdate = 0;
bool _isForeground = true; // starts out assumed to be in foreground
bool _inPaint = false;
bool _isGLInitialized { false };

View file

@ -117,11 +117,15 @@ void Stats::updateStats(bool force) {
// we need to take one avatar out so we don't include ourselves
STAT_UPDATE(avatarCount, avatarManager->size() - 1);
STAT_UPDATE(serverCount, (int)nodeList->size());
STAT_UPDATE(renderrate, (int)qApp->getFps());
STAT_UPDATE(renderrate, qApp->getFps());
if (qApp->getActiveDisplayPlugin()) {
STAT_UPDATE(presentrate, (int)round(qApp->getActiveDisplayPlugin()->presentRate()));
STAT_UPDATE(presentrate, qApp->getActiveDisplayPlugin()->presentRate());
STAT_UPDATE(presentnewrate, qApp->getActiveDisplayPlugin()->newFramePresentRate());
STAT_UPDATE(presentdroprate, qApp->getActiveDisplayPlugin()->droppedFrameRate());
} else {
STAT_UPDATE(presentrate, -1);
STAT_UPDATE(presentnewrate, -1);
STAT_UPDATE(presentdroprate, -1);
}
STAT_UPDATE(simrate, (int)qApp->getAverageSimsPerSecond());
STAT_UPDATE(avatarSimrate, (int)qApp->getAvatarSimrate());

View file

@ -32,8 +32,10 @@ class Stats : public QQuickItem {
Q_PROPERTY(float audioPacketlossDownstream READ getAudioPacketLossDownstream)
STATS_PROPERTY(int, serverCount, 0)
STATS_PROPERTY(int, renderrate, 0)
STATS_PROPERTY(int, presentrate, 0)
STATS_PROPERTY(float, renderrate, 0)
STATS_PROPERTY(float, presentrate, 0)
STATS_PROPERTY(float, presentnewrate, 0)
STATS_PROPERTY(float, presentdroprate, 0)
STATS_PROPERTY(int, simrate, 0)
STATS_PROPERTY(int, avatarSimrate, 0)
STATS_PROPERTY(int, avatarCount, 0)
@ -117,6 +119,8 @@ signals:
void serverCountChanged();
void renderrateChanged();
void presentrateChanged();
void presentnewrateChanged();
void presentdroprateChanged();
void simrateChanged();
void avatarSimrateChanged();
void avatarCountChanged();

View file

@ -30,8 +30,6 @@ bool Basic2DWindowOpenGLDisplayPlugin::internalActivate() {
}
}, true, false);
updateFramerate();
return Parent::internalActivate();
}

View file

@ -20,7 +20,7 @@ class Basic2DWindowOpenGLDisplayPlugin : public OpenGLDisplayPlugin {
public:
virtual const QString& getName() const override { return NAME; }
virtual float getTargetFrameRate() override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; }
virtual float getTargetFrameRate() const override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; }
virtual bool internalActivate() override;

View file

@ -30,6 +30,7 @@
#include <CursorManager.h>
#include "CompositorHelper.h"
#if THREADED_PRESENT
// FIXME, for display plugins that don't block on something like vsync, just
@ -415,25 +416,18 @@ void OpenGLDisplayPlugin::updateTextures() {
if (_sceneTextureEscrow.fetchAndReleaseWithGpuWait(_currentSceneTexture)) {
#endif
updateFrameData();
}
_newFrameRate.increment();
}
_overlayTextureEscrow.fetchSignaledAndRelease(_currentOverlayTexture);
}
void OpenGLDisplayPlugin::updateFrameData() {
Lock lock(_mutex);
auto previousFrameIndex = _currentRenderFrameIndex;
_currentRenderFrameIndex = _sceneTextureToFrameIndexMap[_currentSceneTexture];
}
void OpenGLDisplayPlugin::updateFramerate() {
uint64_t now = usecTimestampNow();
static uint64_t lastSwapEnd { now };
uint64_t diff = now - lastSwapEnd;
lastSwapEnd = now;
if (diff != 0) {
Lock lock(_mutex);
_usecsPerFrame.updateAverage(diff);
}
auto skippedCount = (_currentRenderFrameIndex - previousFrameIndex) - 1;
_droppedFrameRate.increment(skippedCount);
}
void OpenGLDisplayPlugin::compositeOverlay() {
@ -545,19 +539,20 @@ void OpenGLDisplayPlugin::present() {
compositeLayers();
// Take the composite framebuffer and send it to the output device
internalPresent();
updateFramerate();
_presentRate.increment();
}
}
float OpenGLDisplayPlugin::presentRate() {
float result { -1.0f };
{
Lock lock(_mutex);
result = _usecsPerFrame.getAverage();
}
result = 1.0f / result;
result *= USECS_PER_SECOND;
return result;
float OpenGLDisplayPlugin::newFramePresentRate() const {
return _newFrameRate.rate();
}
float OpenGLDisplayPlugin::droppedFrameRate() const {
return _droppedFrameRate.rate();
}
float OpenGLDisplayPlugin::presentRate() const {
return _presentRate.rate();
}
void OpenGLDisplayPlugin::drawUnitQuad() {

View file

@ -10,6 +10,7 @@
#include "DisplayPlugin.h"
#include <condition_variable>
#include <memory>
#include <QtCore/QTimer>
#include <QtGui/QImage>
@ -18,6 +19,7 @@
#include <SimpleMovingAverage.h>
#include <gl/OglplusHelpers.h>
#include <gl/GLEscrow.h>
#include <shared/RateCounter.h>
#define THREADED_PRESENT 1
@ -41,7 +43,6 @@ public:
void submitSceneTexture(uint32_t frameIndex, const gpu::TexturePointer& sceneTexture) override;
void submitOverlayTexture(const gpu::TexturePointer& overlayTexture) override;
float presentRate() override;
glm::uvec2 getRecommendedRenderSize() const override {
return getSurfacePixels();
@ -53,6 +54,12 @@ public:
QImage getScreenshot() const override;
float presentRate() const override;
float newFramePresentRate() const override;
float droppedFrameRate() const override;
protected:
#if THREADED_PRESENT
friend class PresentThread;
@ -88,7 +95,6 @@ protected:
void present();
void updateTextures();
void updateFramerate();
void drawUnitQuad();
void swapBuffers();
void eyeViewport(Eye eye) const;
@ -101,7 +107,9 @@ protected:
ShapeWrapperPtr _plane;
mutable Mutex _mutex;
SimpleMovingAverage _usecsPerFrame { 10 };
RateCounter<> _droppedFrameRate;
RateCounter<> _newFrameRate;
RateCounter<> _presentRate;
QMap<gpu::TexturePointer, uint32_t> _sceneTextureToFrameIndexMap;
uint32_t _currentRenderFrameIndex { 0 };

View file

@ -66,7 +66,7 @@ public:
/// By default, all HMDs are stereo
virtual bool isStereo() const { return isHmd(); }
virtual bool isThrottled() const { return false; }
virtual float getTargetFrameRate() { return 0.0f; }
virtual float getTargetFrameRate() const { return 0.0f; }
/// Returns a boolean value indicating whether the display is currently visible
/// to the user. For monitor displays, false might indicate that a screensaver,
@ -142,7 +142,12 @@ public:
virtual void abandonCalibration() {}
virtual void resetSensors() {}
virtual float devicePixelRatio() { return 1.0f; }
virtual float presentRate() { return -1.0f; }
// Rate at which we present to the display device
virtual float presentRate() const { return -1.0f; }
// Rate at which new frames are being presented to the display device
virtual float newFramePresentRate() const { return -1.0f; }
// Rate at which rendered frames are being skipped
virtual float droppedFrameRate() const { return -1.0f; }
uint32_t presentCount() const { return _presentedFrameIndex; }
virtual void cycleDebugOutput() {}

View file

@ -0,0 +1,47 @@
//
// Created by Bradley Austin Davis 2016/04/10
// Copyright 2013-2016 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#pragma once
#ifndef hifi_Shared_RateCounter_h
#define hifi_Shared_RateCounter_h
#include <stdint.h>
#include <functional>
#include <QtCore/QElapsedTimer>
#include "../SharedUtil.h"
#include "../NumericalConstants.h"
template <uint32_t INTERVAL = MSECS_PER_SECOND, uint8_t PRECISION = 2>
class RateCounter {
public:
void increment(size_t count = 1) {
auto now = usecTimestampNow();
auto currentIntervalMs = (uint32_t)((now - _start) / USECS_PER_MSEC);
if (currentIntervalMs > INTERVAL) {
float currentCount = _count;
float intervalSeconds = (float)currentIntervalMs / (float)MSECS_PER_SECOND;
_rate = roundf(currentCount / intervalSeconds * _scale) / _scale;
};
_count += count;
}
float rate() const { return _rate; }
uint8_t precision() const { return PRECISION; }
uint32_t interval() const { return INTERVAL; }
private:
uint64_t _start { usecTimestampNow() };
size_t _count { 0 };
float _rate { 0 };
const float _scale { powf(10, PRECISION) };
};
#endif

View file

@ -21,7 +21,7 @@ public:
// Stereo specific methods
virtual void resetSensors() override final;
virtual void beginFrameRender(uint32_t frameIndex) override;
float getTargetFrameRate() override { return _hmdDesc.DisplayRefreshRate; }
float getTargetFrameRate() const override { return _hmdDesc.DisplayRefreshRate; }
protected:

View file

@ -181,7 +181,7 @@ int OculusLegacyDisplayPlugin::getHmdScreen() const {
return _hmdScreen;
}
float OculusLegacyDisplayPlugin::getTargetFrameRate() {
float OculusLegacyDisplayPlugin::getTargetFrameRate() const {
return TARGET_RATE_OculusLegacy;
}

View file

@ -28,7 +28,7 @@ public:
virtual void resetSensors() override;
virtual void beginFrameRender(uint32_t frameIndex) override;
virtual float getTargetFrameRate() override;
virtual float getTargetFrameRate() const override;
protected:
virtual bool internalActivate() override;

View file

@ -21,7 +21,7 @@ public:
virtual bool isSupported() const override;
virtual const QString& getName() const override { return NAME; }
virtual float getTargetFrameRate() override { return TARGET_RATE_OpenVr; }
virtual float getTargetFrameRate() const override { return TARGET_RATE_OpenVr; }
virtual void customizeContext() override;