merge from upstream

This commit is contained in:
Seth Alves 2015-12-10 11:21:36 -08:00
commit d10221f53a
11 changed files with 136 additions and 66 deletions

View file

@ -3236,6 +3236,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
bool Application::isHMDMode() const { bool Application::isHMDMode() const {
return getActiveDisplayPlugin()->isHmd(); return getActiveDisplayPlugin()->isHmd();
} }
float Application::getTargetFrameRate() { return getActiveDisplayPlugin()->getTargetFrameRate(); }
QRect Application::getDesirableApplicationGeometry() { QRect Application::getDesirableApplicationGeometry() {
QRect applicationGeometry = getWindow()->geometry(); QRect applicationGeometry = getWindow()->geometry();
@ -4049,7 +4050,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable); scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable);
connect(scriptEngine, SIGNAL(finished(const QString&)), clipboardScriptable, SLOT(deleteLater())); connect(scriptEngine, SIGNAL(finished(const QString&)), clipboardScriptable, SLOT(deleteLater()));
connect(scriptEngine, SIGNAL(finished(const QString&)), this, SLOT(scriptFinished(const QString&))); connect(scriptEngine, &ScriptEngine::finished, this, &Application::scriptFinished, Qt::DirectConnection);
connect(scriptEngine, SIGNAL(loadScript(const QString&, bool)), this, SLOT(loadScript(const QString&, bool))); connect(scriptEngine, SIGNAL(loadScript(const QString&, bool)), this, SLOT(loadScript(const QString&, bool)));
connect(scriptEngine, SIGNAL(reloadScript(const QString&, bool)), this, SLOT(reloadScript(const QString&, bool))); connect(scriptEngine, SIGNAL(reloadScript(const QString&, bool)), this, SLOT(reloadScript(const QString&, bool)));
@ -4295,10 +4296,13 @@ ScriptEngine* Application::loadScript(const QString& scriptFilename, bool isUser
QUrl scriptUrl(scriptFilename); QUrl scriptUrl(scriptFilename);
const QString& scriptURLString = scriptUrl.toString(); const QString& scriptURLString = scriptUrl.toString();
if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor {
&& !_scriptEnginesHash[scriptURLString]->isFinished()) { QReadLocker lock(&_scriptEnginesHashLock);
if (_scriptEnginesHash.contains(scriptURLString) && loadScriptFromEditor
&& !_scriptEnginesHash[scriptURLString]->isFinished()) {
return _scriptEnginesHash[scriptURLString]; return _scriptEnginesHash[scriptURLString];
}
} }
ScriptEngine* scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface); ScriptEngine* scriptEngine = new ScriptEngine(NO_SCRIPT, "", &_controllerScriptingInterface);
@ -4338,7 +4342,11 @@ void Application::reloadScript(const QString& scriptName, bool isUserLoaded) {
void Application::handleScriptEngineLoaded(const QString& scriptFilename) { void Application::handleScriptEngineLoaded(const QString& scriptFilename) {
ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender()); ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender());
_scriptEnginesHash.insertMulti(scriptFilename, scriptEngine); {
QWriteLocker lock(&_scriptEnginesHashLock);
_scriptEnginesHash.insertMulti(scriptFilename, scriptEngine);
}
_runningScriptsWidget->setRunningScripts(getRunningScripts()); _runningScriptsWidget->setRunningScripts(getRunningScripts());
UserActivityLogger::getInstance().loadedScript(scriptFilename); UserActivityLogger::getInstance().loadedScript(scriptFilename);
@ -4353,55 +4361,88 @@ void Application::handleScriptLoadError(const QString& scriptFilename) {
QMessageBox::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load."); QMessageBox::warning(getWindow(), "Error Loading Script", scriptFilename + " failed to load.");
} }
void Application::scriptFinished(const QString& scriptName) { QStringList Application::getRunningScripts() {
const QString& scriptURLString = QUrl(scriptName).toString(); QReadLocker lock(&_scriptEnginesHashLock);
QHash<QString, ScriptEngine*>::iterator it = _scriptEnginesHash.find(scriptURLString); return _scriptEnginesHash.keys();
if (it != _scriptEnginesHash.end()) { }
_scriptEnginesHash.erase(it);
_runningScriptsWidget->scriptStopped(scriptName); ScriptEngine* Application::getScriptEngine(const QString& scriptHash) {
_runningScriptsWidget->setRunningScripts(getRunningScripts()); QReadLocker lock(&_scriptEnginesHashLock);
return _scriptEnginesHash.value(scriptHash, nullptr);
}
void Application::scriptFinished(const QString& scriptName, ScriptEngine* engine) {
bool removed = false;
{
QWriteLocker lock(&_scriptEnginesHashLock);
const QString& scriptURLString = QUrl(scriptName).toString();
for (auto it = _scriptEnginesHash.find(scriptURLString); it != _scriptEnginesHash.end(); ++it) {
if (it.value() == engine) {
_scriptEnginesHash.erase(it);
removed = true;
break;
}
}
}
if (removed) {
postLambdaEvent([this, scriptName]() {
_runningScriptsWidget->scriptStopped(scriptName);
_runningScriptsWidget->setRunningScripts(getRunningScripts());
});
} }
} }
void Application::stopAllScripts(bool restart) { void Application::stopAllScripts(bool restart) {
if (restart) { {
// Delete all running scripts from cache so that they are re-downloaded when they are restarted QReadLocker lock(&_scriptEnginesHashLock);
auto scriptCache = DependencyManager::get<ScriptCache>();
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin(); if (restart) {
// Delete all running scripts from cache so that they are re-downloaded when they are restarted
auto scriptCache = DependencyManager::get<ScriptCache>();
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
it != _scriptEnginesHash.constEnd(); it++) { it != _scriptEnginesHash.constEnd(); it++) {
if (!it.value()->isFinished()) { if (!it.value()->isFinished()) {
scriptCache->deleteScript(it.key()); scriptCache->deleteScript(it.key());
}
} }
} }
}
// Stop and possibly restart all currently running scripts // Stop and possibly restart all currently running scripts
for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin(); for (QHash<QString, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
it != _scriptEnginesHash.constEnd(); it++) { it != _scriptEnginesHash.constEnd(); it++) {
if (it.value()->isFinished()) { if (it.value()->isFinished()) {
continue; continue;
}
if (restart && it.value()->isUserLoaded()) {
connect(it.value(), &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) {
reloadScript(scriptName);
});
}
QMetaObject::invokeMethod(it.value(), "stop");
//it.value()->stop();
qCDebug(interfaceapp) << "stopping script..." << it.key();
} }
if (restart && it.value()->isUserLoaded()) {
connect(it.value(), SIGNAL(finished(const QString&)), SLOT(reloadScript(const QString&)));
}
it.value()->stop();
qCDebug(interfaceapp) << "stopping script..." << it.key();
} }
getMyAvatar()->clearScriptableSettings(); getMyAvatar()->clearScriptableSettings();
} }
bool Application::stopScript(const QString& scriptHash, bool restart) { bool Application::stopScript(const QString& scriptHash, bool restart) {
bool stoppedScript = false; bool stoppedScript = false;
if (_scriptEnginesHash.contains(scriptHash)) { {
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash]; QReadLocker lock(&_scriptEnginesHashLock);
if (restart) { if (_scriptEnginesHash.contains(scriptHash)) {
auto scriptCache = DependencyManager::get<ScriptCache>(); ScriptEngine* scriptEngine = _scriptEnginesHash[scriptHash];
scriptCache->deleteScript(QUrl(scriptHash)); if (restart) {
connect(scriptEngine, SIGNAL(finished(const QString&)), SLOT(reloadScript(const QString&))); auto scriptCache = DependencyManager::get<ScriptCache>();
scriptCache->deleteScript(QUrl(scriptHash));
connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) {
reloadScript(scriptName);
});
}
scriptEngine->stop();
stoppedScript = true;
qCDebug(interfaceapp) << "stopping script..." << scriptHash;
} }
scriptEngine->stop();
stoppedScript = true;
qCDebug(interfaceapp) << "stopping script..." << scriptHash;
} }
if (_scriptEnginesHash.empty()) { if (_scriptEnginesHash.empty()) {
getMyAvatar()->clearScriptableSettings(); getMyAvatar()->clearScriptableSettings();
@ -4420,6 +4461,7 @@ void Application::reloadOneScript(const QString& scriptName) {
} }
void Application::loadDefaultScripts() { void Application::loadDefaultScripts() {
QReadLocker lock(&_scriptEnginesHashLock);
if (!_scriptEnginesHash.contains(DEFAULT_SCRIPTS_JS_URL)) { if (!_scriptEnginesHash.contains(DEFAULT_SCRIPTS_JS_URL)) {
loadScript(DEFAULT_SCRIPTS_JS_URL); loadScript(DEFAULT_SCRIPTS_JS_URL);
} }

View file

@ -160,9 +160,7 @@ public:
uint32_t getFrameCount() { return _frameCount; } uint32_t getFrameCount() { return _frameCount; }
float getFps() const { return _fps; } float getFps() const { return _fps; }
float const HMD_TARGET_FRAME_RATE = 75.0f; float getTargetFrameRate(); // frames/second
float const DESKTOP_TARGET_FRAME_RATE = 60.0f;
float getTargetFrameRate() { return isHMDMode() ? HMD_TARGET_FRAME_RATE : DESKTOP_TARGET_FRAME_RATE; }
float getLastInstanteousFps() const { return _lastInstantaneousFps; } float getLastInstanteousFps() const { return _lastInstantaneousFps; }
float getLastUnsynchronizedFps() const { return _lastUnsynchronizedFps; } float getLastUnsynchronizedFps() const { return _lastUnsynchronizedFps; }
@ -199,8 +197,8 @@ public:
NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; } NodeToJurisdictionMap& getEntityServerJurisdictions() { return _entityServerJurisdictions; }
QStringList getRunningScripts() { return _scriptEnginesHash.keys(); } QStringList getRunningScripts();
ScriptEngine* getScriptEngine(const QString& scriptHash) { return _scriptEnginesHash.value(scriptHash, NULL); } ScriptEngine* getScriptEngine(const QString& scriptHash);
float getRenderResolutionScale() const; float getRenderResolutionScale() const;
@ -333,7 +331,7 @@ private slots:
void loadSettings(); void loadSettings();
void saveSettings(); void saveSettings();
void scriptFinished(const QString& scriptName); void scriptFinished(const QString& scriptName, ScriptEngine* engine);
void saveScripts(); void saveScripts();
void reloadScript(const QString& scriptName, bool isUserLoaded = true); void reloadScript(const QString& scriptName, bool isUserLoaded = true);
@ -500,6 +498,7 @@ private:
TouchEvent _lastTouchEvent; TouchEvent _lastTouchEvent;
QReadWriteLock _scriptEnginesHashLock;
RunningScriptsWidget* _runningScriptsWidget; RunningScriptsWidget* _runningScriptsWidget;
QHash<QString, ScriptEngine*> _scriptEnginesHash; QHash<QString, ScriptEngine*> _scriptEnginesHash;
bool _runningScriptsWidgetWasVisible; bool _runningScriptsWidgetWasVisible;

View file

@ -145,13 +145,19 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
PerformanceTimer perfTimer("otherAvatars"); PerformanceTimer perfTimer("otherAvatars");
_renderDistanceController.setMeasuredValueSetpoint(qApp->getTargetFrameRate()); // No problem updating in flight. float distance;
// The PID controller raises the controlled value when the measured value goes up. if (!qApp->isThrottleRendering()) {
// The measured value is frame rate. When the controlled value (1 / render cutoff distance) _renderDistanceController.setMeasuredValueSetpoint(qApp->getTargetFrameRate()); // No problem updating in flight.
// goes up, the render cutoff distance gets closer, the number of rendered avatars is less, and frame rate // The PID controller raises the controlled value when the measured value goes up.
// goes up. // The measured value is frame rate. When the controlled value (1 / render cutoff distance)
const float deduced = qApp->getLastUnsynchronizedFps(); // goes up, the render cutoff distance gets closer, the number of rendered avatars is less, and frame rate
const float distance = 1.0f / _renderDistanceController.update(deduced, deltaTime); // goes up.
const float deduced = qApp->getLastUnsynchronizedFps();
distance = 1.0f / _renderDistanceController.update(deduced, deltaTime);
} else {
// Here we choose to just use the maximum render cutoff distance if throttled.
distance = 1.0f / _renderDistanceController.getControlledValueLowLimit();
}
_renderDistanceAverage.updateAverage(distance); _renderDistanceAverage.updateAverage(distance);
_renderDistance = _renderDistanceAverage.getAverage(); _renderDistance = _renderDistanceAverage.getAverage();
int renderableCount = 0; int renderableCount = 0;

View file

@ -83,16 +83,16 @@ void Basic2DWindowOpenGLDisplayPlugin::internalPresent() {
} }
WindowOpenGLDisplayPlugin::internalPresent(); WindowOpenGLDisplayPlugin::internalPresent();
} }
const uint32_t THROTTLED_FRAMERATE = 15;
int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const { int Basic2DWindowOpenGLDisplayPlugin::getDesiredInterval() const {
static const int THROTTLED_PAINT_TIMER_DELAY_MS = MSECS_PER_SECOND / 15;
static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1; static const int ULIMIITED_PAINT_TIMER_DELAY_MS = 1;
int result = ULIMIITED_PAINT_TIMER_DELAY_MS; int result = ULIMIITED_PAINT_TIMER_DELAY_MS;
if (_isThrottled) {
result = THROTTLED_PAINT_TIMER_DELAY_MS;
}
if (0 != _framerateTarget) { if (0 != _framerateTarget) {
result = MSECS_PER_SECOND / _framerateTarget; result = MSECS_PER_SECOND / _framerateTarget;
} else if (_isThrottled) {
// This test wouldn't be necessary if we could depend on updateFramerate setting _framerateTarget.
// Alas, that gets complicated: isThrottled() is const and other stuff depends on it.
result = MSECS_PER_SECOND / THROTTLED_FRAMERATE;
} }
return result; return result;
@ -111,7 +111,6 @@ bool Basic2DWindowOpenGLDisplayPlugin::isThrottled() const {
return shouldThrottle; return shouldThrottle;
} }
void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() { void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() {
QAction* checkedFramerate{ nullptr }; QAction* checkedFramerate{ nullptr };
foreach(auto action, _framerateActions) { foreach(auto action, _framerateActions) {
@ -133,9 +132,12 @@ void Basic2DWindowOpenGLDisplayPlugin::updateFramerate() {
} else if (FRAMERATE_30 == actionText) { } else if (FRAMERATE_30 == actionText) {
_framerateTarget = 30; _framerateTarget = 30;
} }
} } else if (_isThrottled) {
_framerateTarget = THROTTLED_FRAMERATE;
}
_timer.start(getDesiredInterval()); int newInterval = getDesiredInterval();
_timer.start(newInterval);
} }
// FIXME target the screen the window is currently on // FIXME target the screen the window is currently on

View file

@ -9,6 +9,8 @@
#include "WindowOpenGLDisplayPlugin.h" #include "WindowOpenGLDisplayPlugin.h"
const float TARGET_FRAMERATE_Basic2DWindowOpenGL = 60.0f;
class QScreen; class QScreen;
class QAction; class QAction;
@ -18,6 +20,8 @@ class Basic2DWindowOpenGLDisplayPlugin : public WindowOpenGLDisplayPlugin {
public: public:
virtual const QString & getName() const override; virtual const QString & getName() const override;
virtual float getTargetFrameRate() override { return _framerateTarget ? (float) _framerateTarget : TARGET_FRAMERATE_Basic2DWindowOpenGL; }
virtual void activate() override; virtual void activate() override;
virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override; virtual void submitSceneTexture(uint32_t frameIndex, uint32_t sceneTexture, const glm::uvec2& sceneSize) override;

View file

@ -58,6 +58,7 @@ public:
/// By default, all HMDs are stereo /// By default, all HMDs are stereo
virtual bool isStereo() const { return isHmd(); } virtual bool isStereo() const { return isHmd(); }
virtual bool isThrottled() const { return false; } virtual bool isThrottled() const { return false; }
virtual float getTargetFrameRate() { return 0.0f; }
// Rendering support // Rendering support

View file

@ -183,7 +183,7 @@ void ScriptEngine::runInThread() {
QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines; QSet<ScriptEngine*> ScriptEngine::_allKnownScriptEngines;
QMutex ScriptEngine::_allScriptsMutex; QMutex ScriptEngine::_allScriptsMutex;
bool ScriptEngine::_stoppingAllScripts = false; std::atomic<bool> ScriptEngine::_stoppingAllScripts { false };
void ScriptEngine::stopAllScripts(QObject* application) { void ScriptEngine::stopAllScripts(QObject* application) {
_allScriptsMutex.lock(); _allScriptsMutex.lock();
@ -752,7 +752,7 @@ void ScriptEngine::run() {
} }
if (_wantSignals) { if (_wantSignals) {
emit finished(_fileNameString); emit finished(_fileNameString, this);
} }
_isRunning = false; _isRunning = false;
@ -775,6 +775,10 @@ void ScriptEngine::stopAllTimers() {
void ScriptEngine::stop() { void ScriptEngine::stop() {
if (!_isFinished) { if (!_isFinished) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "stop");
return;
}
_isFinished = true; _isFinished = true;
if (_wantSignals) { if (_wantSignals) {
emit runningStateChanged(); emit runningStateChanged();

View file

@ -153,7 +153,7 @@ signals:
void errorLoadingScript(const QString& scriptFilename); void errorLoadingScript(const QString& scriptFilename);
void update(float deltaTime); void update(float deltaTime);
void scriptEnding(); void scriptEnding();
void finished(const QString& fileNameString); void finished(const QString& fileNameString, ScriptEngine* engine);
void cleanupMenuItem(const QString& menuItemString); void cleanupMenuItem(const QString& menuItemString);
void printedMessage(const QString& message); void printedMessage(const QString& message);
void errorMessage(const QString& message); void errorMessage(const QString& message);
@ -166,8 +166,8 @@ signals:
protected: protected:
QString _scriptContents; QString _scriptContents;
QString _parentURL; QString _parentURL;
bool _isFinished { false }; std::atomic<bool> _isFinished { false };
bool _isRunning { false }; std::atomic<bool> _isRunning { false };
int _evaluatesPending { 0 }; int _evaluatesPending { 0 };
bool _isInitialized { false }; bool _isInitialized { false };
QHash<QTimer*, QScriptValue> _timerFunctionMap; QHash<QTimer*, QScriptValue> _timerFunctionMap;
@ -193,7 +193,7 @@ protected:
Quat _quatLibrary; Quat _quatLibrary;
Vec3 _vec3Library; Vec3 _vec3Library;
ScriptUUID _uuidLibrary; ScriptUUID _uuidLibrary;
bool _isUserLoaded { false }; std::atomic<bool> _isUserLoaded { false };
bool _isReloading { false }; bool _isReloading { false };
ArrayBufferClass* _arrayBufferClass; ArrayBufferClass* _arrayBufferClass;
@ -206,7 +206,7 @@ protected:
static QSet<ScriptEngine*> _allKnownScriptEngines; static QSet<ScriptEngine*> _allKnownScriptEngines;
static QMutex _allScriptsMutex; static QMutex _allScriptsMutex;
static bool _stoppingAllScripts; static std::atomic<bool> _stoppingAllScripts;
}; };
#endif // hifi_ScriptEngine_h #endif // hifi_ScriptEngine_h

View file

@ -12,12 +12,16 @@
struct SwapFramebufferWrapper; struct SwapFramebufferWrapper;
using SwapFboPtr = QSharedPointer<SwapFramebufferWrapper>; using SwapFboPtr = QSharedPointer<SwapFramebufferWrapper>;
const float TARGET_RATE_Oculus = 75.0f;
class OculusDisplayPlugin : public OculusBaseDisplayPlugin { class OculusDisplayPlugin : public OculusBaseDisplayPlugin {
public: public:
virtual void activate() override; virtual void activate() override;
virtual const QString & getName() const override; virtual const QString & getName() const override;
virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final; virtual void setEyeRenderPose(uint32_t frameIndex, Eye eye, const glm::mat4& pose) override final;
virtual float getTargetFrameRate() override { return TARGET_RATE_Oculus; }
protected: protected:
virtual void internalPresent() override; virtual void internalPresent() override;
virtual void customizeContext() override; virtual void customizeContext() override;

View file

@ -13,6 +13,8 @@
#include <OVR_CAPI.h> #include <OVR_CAPI.h>
const float TARGET_RATE_OculusLegacy = 75.0f;
class OculusLegacyDisplayPlugin : public WindowOpenGLDisplayPlugin { class OculusLegacyDisplayPlugin : public WindowOpenGLDisplayPlugin {
public: public:
OculusLegacyDisplayPlugin(); OculusLegacyDisplayPlugin();
@ -25,6 +27,8 @@ public:
virtual bool eventFilter(QObject* receiver, QEvent* event) override; virtual bool eventFilter(QObject* receiver, QEvent* event) override;
virtual int getHmdScreen() const override; virtual int getHmdScreen() const override;
virtual float getTargetFrameRate() override { return TARGET_RATE_OculusLegacy; }
// Stereo specific methods // Stereo specific methods
virtual bool isHmd() const override { return true; } virtual bool isHmd() const override { return true; }
virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override; virtual glm::mat4 getProjection(Eye eye, const glm::mat4& baseProjection) const override;

View file

@ -13,12 +13,16 @@
#include <display-plugins/WindowOpenGLDisplayPlugin.h> #include <display-plugins/WindowOpenGLDisplayPlugin.h>
const float TARGET_RATE_OpenVr = 90.0f; // FIXME: get from sdk tracked device property? This number is vive-only.
class OpenVrDisplayPlugin : public WindowOpenGLDisplayPlugin { class OpenVrDisplayPlugin : public WindowOpenGLDisplayPlugin {
public: public:
virtual bool isSupported() const override; virtual bool isSupported() const override;
virtual const QString & getName() const override; virtual const QString & getName() const override;
virtual bool isHmd() const override { return true; } virtual bool isHmd() const override { return true; }
virtual float getTargetFrameRate() override { return TARGET_RATE_OpenVr; }
virtual void activate() override; virtual void activate() override;
virtual void deactivate() override; virtual void deactivate() override;