From c7a28a527a2f487ad5534189e17690d3231586ba Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Apr 2017 10:56:25 -0700 Subject: [PATCH 01/27] cleanup Agent recording handling, make loadRecording async --- assignment-client/src/Agent.cpp | 25 ++++++++- assignment-client/src/Agent.h | 6 +- interface/src/Application.cpp | 5 ++ .../networking/src/NetworkAccessManager.cpp | 1 - .../recording/src/recording/ClipCache.cpp | 21 +++++-- libraries/recording/src/recording/ClipCache.h | 16 ++++-- .../src/RecordingScriptingInterface.cpp | 56 ++++++++++++------- .../src/RecordingScriptingInterface.h | 10 +++- libraries/shared/src/DependencyManager.h | 2 +- libraries/shared/src/SharedUtil.cpp | 2 +- 10 files changed, 107 insertions(+), 37 deletions(-) diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index e28c04379f..561d9aa209 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -33,6 +33,7 @@ #include #include +#include #include #include #include @@ -53,7 +54,8 @@ static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 10; Agent::Agent(ReceivedMessage& message) : ThreadedAssignment(message), - _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) { + _receivedAudioStream(RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES, RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES) +{ DependencyManager::get()->setPacketSender(&_entityEditSender); ResourceManager::init(); @@ -64,12 +66,16 @@ Agent::Agent(ReceivedMessage& message) : DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); - DependencyManager::set(); + DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(ScriptEngine::AGENT_SCRIPT); + DependencyManager::set(); + auto& packetReceiver = DependencyManager::get()->getPacketReceiver(); packetReceiver.registerListenerForTypes( @@ -327,6 +333,8 @@ void Agent::executeScript() { _scriptEngine = std::unique_ptr(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload)); _scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do + DependencyManager::get()->setScriptEngine(_scriptEngine.get()); + // setup an Avatar for the script to use auto scriptedAvatar = DependencyManager::get(); @@ -470,6 +478,8 @@ void Agent::executeScript() { Frame::clearFrameHandler(AUDIO_FRAME_TYPE); Frame::clearFrameHandler(AVATAR_FRAME_TYPE); + DependencyManager::destroy(); + setFinished(true); } @@ -753,8 +763,19 @@ void Agent::aboutToFinish() { // cleanup the AudioInjectorManager (and any still running injectors) DependencyManager::destroy(); + + // destroy all other created dependencies + DependencyManager::destroy(); DependencyManager::destroy(); + DependencyManager::destroy(); + DependencyManager::destroy(); + DependencyManager::destroy(); + + DependencyManager::destroy(); + DependencyManager::destroy(); + DependencyManager::destroy(); + emit stopAvatarAudioTimer(); _avatarAudioTimerThread.quit(); diff --git a/assignment-client/src/Agent.h b/assignment-client/src/Agent.h index 620ac8e047..2a156aba18 100644 --- a/assignment-client/src/Agent.h +++ b/assignment-client/src/Agent.h @@ -46,9 +46,6 @@ class Agent : public ThreadedAssignment { public: Agent(ReceivedMessage& message); - void setIsAvatar(bool isAvatar); - bool isAvatar() const { return _isAvatar; } - bool isPlayingAvatarSound() const { return _avatarSound != NULL; } bool isListeningToAudioStream() const { return _isListeningToAudioStream; } @@ -65,6 +62,9 @@ public: public slots: void run() override; void playAvatarSound(SharedSoundPointer avatarSound); + + void setIsAvatar(bool isAvatar); + bool isAvatar() const { return _isAvatar; } private slots: void requestScript(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 62917b304c..781d866c0f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -118,6 +118,7 @@ #include #include #include +#include #include #include #include @@ -464,6 +465,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(ScriptEngine::CLIENT_SCRIPT); DependencyManager::set(); + DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); DependencyManager::set(); @@ -5437,6 +5439,9 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri // AvatarManager has some custom types AvatarManager::registerMetaTypes(scriptEngine); + // give the script engine to the RecordingScriptingInterface for its callbacks + DependencyManager::get()->setScriptEngine(scriptEngine); + if (property(hifi::properties::TEST).isValid()) { scriptEngine->registerGlobalObject("Test", TestScriptingInterface::getInstance()); } diff --git a/libraries/networking/src/NetworkAccessManager.cpp b/libraries/networking/src/NetworkAccessManager.cpp index 78a05677fd..73096825e0 100644 --- a/libraries/networking/src/NetworkAccessManager.cpp +++ b/libraries/networking/src/NetworkAccessManager.cpp @@ -19,7 +19,6 @@ QThreadStorage networkAccessManagers; QNetworkAccessManager& NetworkAccessManager::getInstance() { if (!networkAccessManagers.hasLocalData()) { networkAccessManagers.setLocalData(new QNetworkAccessManager()); - } return *networkAccessManagers.localData(); diff --git a/libraries/recording/src/recording/ClipCache.cpp b/libraries/recording/src/recording/ClipCache.cpp index 66d5fb0d88..0665608bad 100644 --- a/libraries/recording/src/recording/ClipCache.cpp +++ b/libraries/recording/src/recording/ClipCache.cpp @@ -5,6 +5,9 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +#include + #include "ClipCache.h" #include "impl/PointerClip.h" @@ -21,18 +24,28 @@ void NetworkClip::init(const QByteArray& clipData) { void NetworkClipLoader::downloadFinished(const QByteArray& data) { _clip->init(data); finishedLoading(true); + emit clipLoaded(); } -ClipCache& ClipCache::instance() { - static ClipCache _instance; - return _instance; +ClipCache::ClipCache(QObject* parent) : + ResourceCache(parent) +{ + } NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) { - return ResourceCache::getResource(url, QUrl(), nullptr).staticCast(); + if (QThread::currentThread() != thread()) { + NetworkClipLoaderPointer result; + QMetaObject::invokeMethod(this, "getClipLoader", Qt::BlockingQueuedConnection, + Q_RETURN_ARG(NetworkClipLoaderPointer, result), Q_ARG(const QUrl&, url)); + return result; + } + + return getResource(url).staticCast(); } QSharedPointer ClipCache::createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) { + qDebug() << "Loading recording at" << url; return QSharedPointer(new NetworkClipLoader(url), &Resource::deleter); } diff --git a/libraries/recording/src/recording/ClipCache.h b/libraries/recording/src/recording/ClipCache.h index 7df83efdbf..2c3465e725 100644 --- a/libraries/recording/src/recording/ClipCache.h +++ b/libraries/recording/src/recording/ClipCache.h @@ -30,26 +30,34 @@ private: }; class NetworkClipLoader : public Resource { + Q_OBJECT public: NetworkClipLoader(const QUrl& url); virtual void downloadFinished(const QByteArray& data) override; ClipPointer getClip() { return _clip; } bool completed() { return _failedToLoad || isLoaded(); } +signals: + void clipLoaded(); + private: const NetworkClip::Pointer _clip; }; using NetworkClipLoaderPointer = QSharedPointer; -class ClipCache : public ResourceCache { -public: - static ClipCache& instance(); - +class ClipCache : public ResourceCache, public Dependency { + Q_OBJECT + SINGLETON_DEPENDENCY + +public slots: NetworkClipLoaderPointer getClipLoader(const QUrl& url); protected: virtual QSharedPointer createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) override; + +private: + ClipCache(QObject* parent = nullptr); }; } diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index 41bb780b47..e76a3859f0 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -52,32 +52,48 @@ float RecordingScriptingInterface::playerLength() const { return _player->length(); } -bool RecordingScriptingInterface::loadRecording(const QString& url) { - using namespace recording; +void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue callback) { + auto clipLoader = DependencyManager::get()->getClipLoader(url); - auto loader = ClipCache::instance().getClipLoader(url); - if (!loader) { - qWarning() << "Clip failed to load from " << url; - return false; - } + // hold a strong pointer to the loading clip so that it has a chance to load + _clipLoaders.insert(clipLoader); - if (!loader->isLoaded()) { - QEventLoop loop; - QObject::connect(loader.data(), &Resource::loaded, &loop, &QEventLoop::quit); - QObject::connect(loader.data(), &Resource::failed, &loop, &QEventLoop::quit); - loop.exec(); - } + auto weakClipLoader = clipLoader.toWeakRef(); - if (!loader->isLoaded()) { - qWarning() << "Clip failed to load from " << url; - return false; - } + // when clip loaded, call the callback with the URL and success boolean + connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, this, [this, weakClipLoader, url, callback]() mutable { - _player->queueClip(loader->getClip()); - return true; + if (auto clipLoader = weakClipLoader.toStrongRef()) { + qCDebug(scriptengine) << "Loaded recording from" << url; + + _player->queueClip(clipLoader->getClip()); + + if (callback.isFunction()) { + QScriptValueList args { true, url }; + callback.call(_scriptEngine->globalObject(), args); + } + + // drop our strong pointer to this clip so it is cleaned up + _clipLoaders.remove(clipLoader); + } + }); + + // when clip load fails, call the callback with the URL and failure boolean + connect(clipLoader.data(), &recording::NetworkClipLoader::failed, this, [this, weakClipLoader, url, callback](QNetworkReply::NetworkError error) mutable { + qCDebug(scriptengine) << "Failed to load recording from" << url; + + if (callback.isFunction()) { + QScriptValueList args { false, url }; + callback.call(_scriptEngine->currentContext()->thisObject(), args); + } + + if (auto clipLoader = weakClipLoader.toStrongRef()) { + // drop out strong pointer to this clip so it is cleaned up + _clipLoaders.remove(clipLoader); + } + }); } - void RecordingScriptingInterface::startPlaying() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "startPlaying", Qt::BlockingQueuedConnection); diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index 9661ee9d80..f6d335b17d 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -15,9 +15,11 @@ #include #include +#include #include #include +class QScriptEngine; class QScriptValue; class RecordingScriptingInterface : public QObject, public Dependency { @@ -26,8 +28,11 @@ class RecordingScriptingInterface : public QObject, public Dependency { public: RecordingScriptingInterface(); + void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; } + public slots: - bool loadRecording(const QString& url); + + void loadRecording(const QString& url, QScriptValue callback = QScriptValue()); void startPlaying(); void pausePlayer(); @@ -79,6 +84,9 @@ protected: Flag _useAttachments { false }; Flag _useSkeletonModel { false }; recording::ClipPointer _lastClip; + + QScriptEngine* _scriptEngine; + QSet _clipLoaders; }; #endif // hifi_RecordingScriptingInterface_h diff --git a/libraries/shared/src/DependencyManager.h b/libraries/shared/src/DependencyManager.h index 719763f706..7a453e63c3 100644 --- a/libraries/shared/src/DependencyManager.h +++ b/libraries/shared/src/DependencyManager.h @@ -21,7 +21,7 @@ #include #define SINGLETON_DEPENDENCY \ - friend class DependencyManager; + friend class ::DependencyManager; class Dependency { public: diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index a7e251f0e0..81a0eed9f3 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -769,7 +769,7 @@ bool similarStrings(const QString& stringA, const QString& stringB) { void disableQtBearerPoll() { // to work around the Qt constant wireless scanning, set the env for polling interval very high - const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT_MAX).toLocal8Bit(); + const QByteArray EXTREME_BEARER_POLL_TIMEOUT = QString::number(INT16_MAX).toLocal8Bit(); qputenv("QT_BEARER_POLL_TIMEOUT", EXTREME_BEARER_POLL_TIMEOUT); } From d66038fff2823f22613004513aa13c3bf479ca1d Mon Sep 17 00:00:00 2001 From: kunalgosar Date: Tue, 21 Mar 2017 16:37:51 -0700 Subject: [PATCH 02/27] press B to exit finger painting --- scripts/system/fingerPaint.js | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/system/fingerPaint.js b/scripts/system/fingerPaint.js index 27206ef9fa..3c44014890 100644 --- a/scripts/system/fingerPaint.js +++ b/scripts/system/fingerPaint.js @@ -328,6 +328,7 @@ controllerMapping.from(Controller.Standard.LeftGrip).to(leftHand.onGripPress); controllerMapping.from(Controller.Standard.RT).to(rightHand.onTriggerPress); controllerMapping.from(Controller.Standard.RightGrip).to(rightHand.onGripPress); + controllerMapping.from(Controller.Standard.B).to(onButtonClicked); Controller.enableMapping(CONTROLLER_MAPPING_NAME); // Connect handController outputs to paintBrush objects. From b8500e45adb4e18b73bae46688ff4613810da91b Mon Sep 17 00:00:00 2001 From: kunalgosar Date: Tue, 4 Apr 2017 15:02:52 -0700 Subject: [PATCH 03/27] added tutorial --- scripts/system/fingerPaint.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/scripts/system/fingerPaint.js b/scripts/system/fingerPaint.js index 3c44014890..9ceec46fb3 100644 --- a/scripts/system/fingerPaint.js +++ b/scripts/system/fingerPaint.js @@ -23,6 +23,7 @@ HIFI_POINT_INDEX_MESSAGE_CHANNEL = "Hifi-Point-Index", HIFI_GRAB_DISABLE_MESSAGE_CHANNEL = "Hifi-Grab-Disable", HIFI_POINTER_DISABLE_MESSAGE_CHANNEL = "Hifi-Pointer-Disable"; + HOW_TO_EXIT_MESSAGE = "Press B on your controller to exit FingerPainting mode"; function paintBrush(name) { // Paints in 3D. @@ -319,6 +320,15 @@ } } + function howToExitTutorial() { + HMD.requestShowHandControllers(); + setControllerPartLayer('button_b', 'highlight'); + Window.alert(HOW_TO_EXIT_MESSAGE); + setControllerPartLayer('button_b', 'blank'); + HMD.requestHideHandControllers(); + Settings.setValue("FingerPaintTutorialComplete", true); + } + function enableProcessing() { // Connect controller API to handController objects. leftHand = handController("left"); @@ -330,6 +340,10 @@ controllerMapping.from(Controller.Standard.RightGrip).to(rightHand.onGripPress); controllerMapping.from(Controller.Standard.B).to(onButtonClicked); Controller.enableMapping(CONTROLLER_MAPPING_NAME); + + if (!Settings.getValue("FingerPaintTutorialComplete")) { + howToExitTutorial(); + } // Connect handController outputs to paintBrush objects. leftBrush = paintBrush("left"); @@ -434,6 +448,17 @@ button.clicked.disconnect(onButtonClicked); tablet.removeButton(button); } + + /** + * A controller in made up of parts, and each part can have multiple "layers," + * which are really just different texures. For example, the "trigger" part + * has "normal" and "highlight" layers. + */ + function setControllerPartLayer(part, layer) { + data = {}; + data[part] = layer; + Messages.sendLocalMessage('Controller-Set-Part-Layer', JSON.stringify(data)); + } setUp(); Script.scriptEnding.connect(tearDown); From a5b10cc51eac56b76b60d07c084665d8f8c51fc7 Mon Sep 17 00:00:00 2001 From: kunalgosar Date: Tue, 4 Apr 2017 15:34:56 -0700 Subject: [PATCH 04/27] alert window to give directions --- scripts/system/fingerPaint.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/system/fingerPaint.js b/scripts/system/fingerPaint.js index 9ceec46fb3..ec3c8af3d9 100644 --- a/scripts/system/fingerPaint.js +++ b/scripts/system/fingerPaint.js @@ -323,7 +323,7 @@ function howToExitTutorial() { HMD.requestShowHandControllers(); setControllerPartLayer('button_b', 'highlight'); - Window.alert(HOW_TO_EXIT_MESSAGE); + messageWindow = Window.alert(HOW_TO_EXIT_MESSAGE); setControllerPartLayer('button_b', 'blank'); HMD.requestHideHandControllers(); Settings.setValue("FingerPaintTutorialComplete", true); From 1b245387565bd141ce467bf7f392d584ef8fe1ef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 5 Apr 2017 11:18:52 -0700 Subject: [PATCH 05/27] modify scripts to use new recording API --- .../BetterClientSimulationBotFromRecording.js | 12 ++++--- script-archive/acScripts/PlayRecordingOnAC.js | 10 +++--- .../acScripts/triggeredRecordingOnAC.js | 11 +++--- script-archive/tests/playbackAcTest.js | 12 ++++--- script-archive/vrShop/cash/shopCashierAC.js | 25 +++++++------ .../vrShop/review/shopReviewerAC.js | 34 ++++++++++-------- .../developer/utilities/record/recorder.js | 35 ++++++++++--------- 7 files changed, 80 insertions(+), 59 deletions(-) diff --git a/script-archive/acScripts/BetterClientSimulationBotFromRecording.js b/script-archive/acScripts/BetterClientSimulationBotFromRecording.js index fafb761729..c276d302e1 100644 --- a/script-archive/acScripts/BetterClientSimulationBotFromRecording.js +++ b/script-archive/acScripts/BetterClientSimulationBotFromRecording.js @@ -138,7 +138,13 @@ Agent.isAvatar = true; Agent.isListeningToAudioStream = true; Avatar.skeletonModelURL = AVATAR_URL; // FIXME - currently setting an avatar while playing a recording doesn't work it will be ignored -Recording.loadRecording(RECORDING_URL); +Recording.loadRecording(RECORDING_URL, function(success) { + if (success) { + Script.update.connect(update); + } else { + print("Failed to load recording from " + RECORDING_URL); + } +}); count = 300; // This is necessary to wait for the audio mixer to connect function update(event) { @@ -174,10 +180,8 @@ function update(event) { +" FT: " + Avatar.getDataRate("faceTrackerOutbound").toFixed(2) + "\n" +" JD: " + Avatar.getDataRate("jointDataOutbound").toFixed(2)); } - + if (!Recording.isPlaying()) { Script.update.disconnect(update); } } - -Script.update.connect(update); diff --git a/script-archive/acScripts/PlayRecordingOnAC.js b/script-archive/acScripts/PlayRecordingOnAC.js index 0961f65079..015f247e4a 100644 --- a/script-archive/acScripts/PlayRecordingOnAC.js +++ b/script-archive/acScripts/PlayRecordingOnAC.js @@ -20,7 +20,11 @@ Avatar.orientation = Quat.fromPitchYawRollDegrees(0, 0, 0); Avatar.scale = 1.0; Agent.isAvatar = true; -Recording.loadRecording(recordingFile); +Recording.loadRecording(recordingFile, function(success) { + if (success) { + Script.update.connect(update); + } +}); count = 300; // This is necessary to wait for the audio mixer to connect function update(event) { @@ -39,10 +43,8 @@ function update(event) { Vec3.print("Playing from ", Avatar.position); count--; } - + if (!Recording.isPlaying()) { Script.update.disconnect(update); } } - -Script.update.connect(update); diff --git a/script-archive/acScripts/triggeredRecordingOnAC.js b/script-archive/acScripts/triggeredRecordingOnAC.js index 9de5173615..c3a87bc44e 100644 --- a/script-archive/acScripts/triggeredRecordingOnAC.js +++ b/script-archive/acScripts/triggeredRecordingOnAC.js @@ -42,10 +42,13 @@ var playRecording = function() { Recording.setPlayerLoop(false); Recording.setPlayerTime(STARTING_TIME); Recording.setPlayerAudioOffset(AUDIO_OFFSET); - Recording.loadRecording(CLIP_URL); - Recording.startPlaying(); - isPlaying = true; - isPlayable = false; // Set this true again after the cooldown period + Recording.loadRecording(CLIP_URL, function(success) { + if (success) { + Recording.startPlaying(); + isPlaying = true; + isPlayable = false; // Set this true again after the cooldown period + } + }); }; Script.update.connect(function(deltaTime) { diff --git a/script-archive/tests/playbackAcTest.js b/script-archive/tests/playbackAcTest.js index 5630b17ed8..51ff1bdf02 100644 --- a/script-archive/tests/playbackAcTest.js +++ b/script-archive/tests/playbackAcTest.js @@ -2,7 +2,7 @@ var origin = {x: 512, y: 512, z: 512}; var millisecondsToWaitBeforeStarting = 2 * 1000; // To give the various servers a chance to start. -var millisecondsToWaitBeforeEnding = 30 * 1000; +var millisecondsToWaitBeforeEnding = 30 * 1000; Avatar.skeletonModelURL = "https://hifi-public.s3.amazonaws.com/marketplace/contents/dd03b8e3-52fb-4ab3-9ac9-3b17e00cd85d/98baa90b3b66803c5d7bd4537fca6993.fst"; //lovejoy Avatar.displayName = "AC Avatar"; @@ -10,9 +10,11 @@ Agent.isAvatar = true; Script.setTimeout(function () { Avatar.position = origin; - Recording.loadRecording("d:/hifi.rec"); - Recording.setPlayerLoop(true); - Recording.startPlaying(); + Recording.loadRecording("d:/hifi.rec", function(success){ + Recording.setPlayerLoop(true); + Recording.startPlaying(); + }); + }, millisecondsToWaitBeforeStarting); @@ -21,4 +23,4 @@ Script.setTimeout(function () { Agent.isAvatar = false; Recording.stopPlaying(); Script.stop(); -}, millisecondsToWaitBeforeEnding); \ No newline at end of file +}, millisecondsToWaitBeforeEnding); diff --git a/script-archive/vrShop/cash/shopCashierAC.js b/script-archive/vrShop/cash/shopCashierAC.js index 1219806e8a..91b45484fd 100644 --- a/script-archive/vrShop/cash/shopCashierAC.js +++ b/script-archive/vrShop/cash/shopCashierAC.js @@ -26,7 +26,7 @@ var PLAY = "Play"; function getAction(channel, message, senderID) { if(subscribed) { print("I'm the agent and I received this: " + message); - + switch(message) { case PLAY: print("Play"); @@ -35,7 +35,7 @@ function getAction(channel, message, senderID) { Recording.startPlaying(); } break; - + default: print("Unknown action: " + action); break; @@ -49,16 +49,19 @@ function update(deltaTime) { totalTime += deltaTime; if (totalTime > WAIT_FOR_AUDIO_MIXER) { - if (!subscribed) { + if (!subscribed) { Messages.subscribe(PLAYBACK_CHANNEL); subscribed = true; - Recording.loadRecording(clip_url); - Recording.setPlayFromCurrentLocation(playFromCurrentLocation); - Recording.setPlayerUseDisplayName(useDisplayName); - Recording.setPlayerUseAttachments(useAttachments); - Recording.setPlayerUseHeadModel(false); - Recording.setPlayerUseSkeletonModel(useAvatarModel); - Agent.isAvatar = true; + Recording.loadRecording(clip_url, function(success) { + if (success) { + Recording.setPlayFromCurrentLocation(playFromCurrentLocation); + Recording.setPlayerUseDisplayName(useDisplayName); + Recording.setPlayerUseAttachments(useAttachments); + Recording.setPlayerUseHeadModel(false); + Recording.setPlayerUseSkeletonModel(useAvatarModel); + Agent.isAvatar = true; + } + }); } } @@ -70,4 +73,4 @@ Messages.messageReceived.connect(function (channel, message, senderID) { } }); -Script.update.connect(update); \ No newline at end of file +Script.update.connect(update); diff --git a/script-archive/vrShop/review/shopReviewerAC.js b/script-archive/vrShop/review/shopReviewerAC.js index 7b7776fe98..c39aaa2f4a 100644 --- a/script-archive/vrShop/review/shopReviewerAC.js +++ b/script-archive/vrShop/review/shopReviewerAC.js @@ -9,7 +9,7 @@ var command = null; -var clip_url = null; +var clip_url = null; var REVIEW_CHANNEL = "reviewChannel"; var playFromCurrentLocation = true; @@ -28,16 +28,16 @@ var HIDE = "Hide"; function getAction(channel, message, senderID) { if(subscribed) { print("I'm the agent and I received this: " + message); - + if (Recording.isPlaying()) { Recording.stopPlaying(); } - + m = JSON.parse(message); - + command = m.command; clip_url = m.clip_url; - + switch(command) { case PLAY: print("Play"); @@ -46,21 +46,25 @@ function getAction(channel, message, senderID) { Recording.startPlaying(); } break; - + case SHOW: print("Show"); - Recording.loadRecording(clip_url); - Agent.isAvatar = true; - Recording.setPlayerTime(0.0); - Recording.startPlaying(); - Recording.stopPlaying(); + Recording.loadRecording(clip_url, function(success){ + if (success) { + Agent.isAvatar = true; + Recording.setPlayerTime(0.0); + Recording.startPlaying(); + Recording.stopPlaying(); + } + }); + break; - + case HIDE: print("Hide"); Agent.isAvatar = false; break; - + default: print("Unknown action: " + action); break; @@ -74,7 +78,7 @@ function update(deltaTime) { totalTime += deltaTime; if (totalTime > WAIT_FOR_AUDIO_MIXER) { - if (!subscribed) { + if (!subscribed) { Messages.subscribe(REVIEW_CHANNEL); subscribed = true; Recording.setPlayFromCurrentLocation(playFromCurrentLocation); @@ -93,4 +97,4 @@ Messages.messageReceived.connect(function (channel, message, senderID) { } }); -Script.update.connect(update); \ No newline at end of file +Script.update.connect(update); diff --git a/scripts/developer/utilities/record/recorder.js b/scripts/developer/utilities/record/recorder.js index ba1c8b0393..b335274372 100644 --- a/scripts/developer/utilities/record/recorder.js +++ b/scripts/developer/utilities/record/recorder.js @@ -55,13 +55,13 @@ function setupToolBar() { } Tool.IMAGE_HEIGHT /= 2; Tool.IMAGE_WIDTH /= 2; - + toolBar = new ToolBar(0, 0, ToolBar.HORIZONTAL); - + toolBar.onMove = onToolbarMove; toolBar.setBack(COLOR_TOOL_BAR, ALPHA_OFF); - + recordIcon = toolBar.addTool({ imageURL: TOOL_ICON_URL + "recording-record.svg", subImage: { x: 0, y: 0, width: Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, @@ -71,7 +71,7 @@ function setupToolBar() { alpha: Recording.isPlaying() ? ALPHA_OFF : ALPHA_ON, visible: true }, true, !Recording.isRecording()); - + var playLoopWidthFactor = 1.65; playIcon = toolBar.addTool({ imageURL: TOOL_ICON_URL + "play-pause.svg", @@ -80,7 +80,7 @@ function setupToolBar() { alpha: (Recording.isRecording() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, visible: true }, false); - + playLoopIcon = toolBar.addTool({ imageURL: TOOL_ICON_URL + "play-and-loop.svg", subImage: { x: 0, y: 0, width: playLoopWidthFactor * Tool.IMAGE_WIDTH, height: Tool.IMAGE_HEIGHT }, @@ -89,10 +89,10 @@ function setupToolBar() { alpha: (Recording.isRecording() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, visible: true }, false); - + timerOffset = toolBar.width + ToolBar.SPACING; spacing = toolBar.addSpacing(0); - + saveIcon = toolBar.addTool({ imageURL: TOOL_ICON_URL + "recording-save.svg", width: Tool.IMAGE_WIDTH, @@ -100,7 +100,7 @@ function setupToolBar() { alpha: (Recording.isRecording() || Recording.isPlaying() || Recording.playerLength() === 0) ? ALPHA_OFF : ALPHA_ON, visible: true }, false); - + loadIcon = toolBar.addTool({ imageURL: TOOL_ICON_URL + "recording-upload.svg", width: Tool.IMAGE_WIDTH, @@ -153,10 +153,10 @@ function onToolbarMove(newX, newY, deltaX, deltaY) { x: newX + timerOffset - ToolBar.SPACING, y: newY }); - + slider.x = newX - ToolBar.SPACING; slider.y = newY - slider.h - ToolBar.SPACING; - + Overlays.editOverlay(slider.background, { x: slider.x, y: slider.y @@ -182,13 +182,13 @@ function updateTimer() { width: timerWidth }); toolBar.changeSpacing(timerWidth + ToolBar.SPACING, spacing); - + if (Recording.isRecording()) { slider.pos = 1.0; } else if (Recording.playerLength() > 0) { slider.pos = Recording.playerElapsed() / Recording.playerLength(); } - + Overlays.editOverlay(slider.foreground, { width: slider.pos * slider.w }); @@ -221,7 +221,7 @@ function moveUI() { function mousePressEvent(event) { var clickedOverlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); - + if (recordIcon === toolBar.clicked(clickedOverlay, false) && !Recording.isPlaying()) { if (!Recording.isRecording()) { Recording.startRecording(); @@ -281,8 +281,11 @@ function mousePressEvent(event) { if (!Recording.isRecording() && !Recording.isPlaying()) { recordingFile = Window.browse("Load recording from file", ".", "Recordings (*.hfr *.rec *.HFR *.REC)"); if (!(recordingFile === "null" || recordingFile === null || recordingFile === "")) { - Recording.loadRecording(recordingFile); - setDefaultPlayerOptions(); + Recording.loadRecording(recordingFile, function(success) { + if (success) { + setDefaultPlayerOptions(); + } + }); } if (Recording.playerLength() > 0) { toolBar.setAlpha(ALPHA_ON, playIcon); @@ -323,7 +326,7 @@ function update() { } updateTimer(); - + if (watchStop && !Recording.isPlaying()) { watchStop = false; toolBar.setAlpha(ALPHA_ON, recordIcon); From 3de760abcb5912fc25758fc78ee9421806b25d0a Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 5 Apr 2017 18:35:06 -0700 Subject: [PATCH 06/27] Introduucing the tag to the scene --- libraries/render/src/render/Scene.h | 6 ++++ libraries/render/src/render/Tag.cpp | 27 ++++++++++++++++ libraries/render/src/render/Tag.h | 49 +++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+) create mode 100644 libraries/render/src/render/Tag.cpp create mode 100644 libraries/render/src/render/Tag.h diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 09a725205d..2440ac2246 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -14,6 +14,7 @@ #include "Item.h" #include "SpatialTree.h" +#include "Tag.h" namespace render { @@ -114,6 +115,11 @@ protected: void removeItems(const ItemIDs& ids); void updateItems(const ItemIDs& ids, UpdateFunctors& functors); + + // The Tag map + std::mutex _tagsMutex; + TagMap _tags; + friend class Engine; }; diff --git a/libraries/render/src/render/Tag.cpp b/libraries/render/src/render/Tag.cpp new file mode 100644 index 0000000000..1ae0720746 --- /dev/null +++ b/libraries/render/src/render/Tag.cpp @@ -0,0 +1,27 @@ +// +// Tag.cpp +// render/src/render +// +// Created by Sam Gateau on 4/4/2017. +// Copyright 2017 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 +// +#include "Tag.h" + +#include "Logging.h" + +using namespace render; + +Tag::Tag(const std::string& name, const ItemIDs items) : + _name(name), + _items(items) +{ + +} + +Tag::~Tag() { + +} + diff --git a/libraries/render/src/render/Tag.h b/libraries/render/src/render/Tag.h new file mode 100644 index 0000000000..eb13a6366a --- /dev/null +++ b/libraries/render/src/render/Tag.h @@ -0,0 +1,49 @@ +// +// Tag.h +// render/src/render +// +// Created by Sam Gateau on 4/4/2017. +// Copyright 2017 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 +// + +#ifndef hifi_render_Tag_h +#define hifi_render_Tag_h + +#include "Item.h" + +namespace render { + + class Tag { + public: + + Tag(const std::string& name, const ItemIDs items); + ~Tag(); + + const std::string& getName() const { return _name; } + + const ItemIDs& getItems() const { return _items; } + + protected: + const std::string _name; + ItemIDs _items; + }; + using Tags = std::vector; + + class TagMap { + public: + using NameMap = std::map; + + TagMap() {} + ~TagMap() {} + + + protected: + NameMap _names; + Tags _values; + }; +} + +#endif \ No newline at end of file From b8cb79113e6a6d6eaa9532f50fb70f4028a80093 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 6 Apr 2017 10:30:24 -0700 Subject: [PATCH 07/27] Nitpicking on the correct name maybe... --- libraries/render/src/render/Scene.h | 8 +++--- .../src/render/{Tag.cpp => Selection.cpp} | 8 +++--- .../render/src/render/{Tag.h => Selection.h} | 26 ++++++------------- 3 files changed, 16 insertions(+), 26 deletions(-) rename libraries/render/src/render/{Tag.cpp => Selection.cpp} (71%) rename libraries/render/src/render/{Tag.h => Selection.h} (57%) diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index 2440ac2246..b9aa6d3d2a 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -14,7 +14,7 @@ #include "Item.h" #include "SpatialTree.h" -#include "Tag.h" +#include "Selection.h" namespace render { @@ -116,9 +116,9 @@ protected: void updateItems(const ItemIDs& ids, UpdateFunctors& functors); - // The Tag map - std::mutex _tagsMutex; - TagMap _tags; + // The Selection map + std::mutex _selectionsMutex; + SelectionMap _selections; friend class Engine; }; diff --git a/libraries/render/src/render/Tag.cpp b/libraries/render/src/render/Selection.cpp similarity index 71% rename from libraries/render/src/render/Tag.cpp rename to libraries/render/src/render/Selection.cpp index 1ae0720746..ba72953455 100644 --- a/libraries/render/src/render/Tag.cpp +++ b/libraries/render/src/render/Selection.cpp @@ -1,5 +1,5 @@ // -// Tag.cpp +// Selection.cpp // render/src/render // // Created by Sam Gateau on 4/4/2017. @@ -8,20 +8,20 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "Tag.h" +#include "Selection.h" #include "Logging.h" using namespace render; -Tag::Tag(const std::string& name, const ItemIDs items) : +Selection::Selection(const std::string& name, const ItemIDs items) : _name(name), _items(items) { } -Tag::~Tag() { +Selection::~Selection() { } diff --git a/libraries/render/src/render/Tag.h b/libraries/render/src/render/Selection.h similarity index 57% rename from libraries/render/src/render/Tag.h rename to libraries/render/src/render/Selection.h index eb13a6366a..64bfb2455f 100644 --- a/libraries/render/src/render/Tag.h +++ b/libraries/render/src/render/Selection.h @@ -1,5 +1,5 @@ // -// Tag.h +// Selection.h // render/src/render // // Created by Sam Gateau on 4/4/2017. @@ -9,18 +9,18 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifndef hifi_render_Tag_h -#define hifi_render_Tag_h +#ifndef hifi_render_Selection_h +#define hifi_render_Selection_h #include "Item.h" namespace render { - class Tag { + class Selection { public: - Tag(const std::string& name, const ItemIDs items); - ~Tag(); + Selection(const std::string& name, const ItemIDs items); + ~Selection(); const std::string& getName() const { return _name; } @@ -30,20 +30,10 @@ namespace render { const std::string _name; ItemIDs _items; }; - using Tags = std::vector; + using Selections = std::vector; - class TagMap { - public: - using NameMap = std::map; + using SelectionMap = std::map; - TagMap() {} - ~TagMap() {} - - - protected: - NameMap _names; - Tags _values; - }; } #endif \ No newline at end of file From 91f315f9ce27e5ff95cb6f4c2a88673ded983bd8 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 6 Apr 2017 11:27:48 -0700 Subject: [PATCH 08/27] Adding the concept of selection to the scene --- libraries/render/src/render/Scene.cpp | 45 ++++++++++++++++++++--- libraries/render/src/render/Scene.h | 21 ++++++++++- libraries/render/src/render/Selection.cpp | 35 +++++++++++++++++- libraries/render/src/render/Selection.h | 15 ++++++-- 4 files changed, 104 insertions(+), 12 deletions(-) diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 537d8c1337..0e77b389a0 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -18,8 +18,8 @@ using namespace render; void Transaction::resetItem(ItemID id, const PayloadPointer& payload) { if (payload) { - _resetItems.push_back(id); - _resetPayloads.push_back(payload); + _resetItems.emplace_back(id); + _resetPayloads.emplace_back(payload); } else { qCDebug(renderlogging) << "WARNING: Transaction::resetItem with a null payload!"; removeItem(id); @@ -27,12 +27,16 @@ void Transaction::resetItem(ItemID id, const PayloadPointer& payload) { } void Transaction::removeItem(ItemID id) { - _removedItems.push_back(id); + _removedItems.emplace_back(id); } void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) { - _updatedItems.push_back(id); - _updateFunctors.push_back(functor); + _updatedItems.emplace_back(id); + _updateFunctors.emplace_back(functor); +} + +void Transaction::resetSelection(const Selection& selection) { + _resetSelections.emplace_back(selection); } void Transaction::merge(const Transaction& transaction) { @@ -41,8 +45,10 @@ void Transaction::merge(const Transaction& transaction) { _removedItems.insert(_removedItems.end(), transaction._removedItems.begin(), transaction._removedItems.end()); _updatedItems.insert(_updatedItems.end(), transaction._updatedItems.begin(), transaction._updatedItems.end()); _updateFunctors.insert(_updateFunctors.end(), transaction._updateFunctors.begin(), transaction._updateFunctors.end()); + _resetSelections.insert(_resetSelections.end(), transaction._resetSelections.begin(), transaction._resetSelections.end()); } + Scene::Scene(glm::vec3 origin, float size) : _masterSpatialTree(origin, size) { @@ -112,6 +118,13 @@ void Scene::processTransactionQueue() { // Update the numItemsAtomic counter AFTER the pending changes went through _numAllocatedItems.exchange(maxID); } + + if (consolidatedTransaction.touchTransactions()) { + std::unique_lock lock(_selectionsMutex); + + // resets and potential NEW items + resetSelections(consolidatedTransaction._resetSelections); + } } void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) { @@ -202,3 +215,25 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) { updateFunctor++; } } + +// THis fucntion is thread safe +Selection Scene::getSelection(const Selection::Name& name) const { + std::unique_lock lock(_selectionsMutex); + auto found = _selections.find(name); + if (found == _selections.end()) { + return Selection(); + } else { + return (*found).second; + } +} + +void Scene::resetSelections(const Selections& selections) { + for (auto selection : selections) { + auto found = _selections.find(selection.getName()); + if (found == _selections.end()) { + _selections.insert(SelectionMap::value_type(selection.getName(), selection)); + } else { + (*found).second = selection; + } + } +} diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index b9aa6d3d2a..fc0a8c1fca 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -34,6 +34,7 @@ public: Transaction() {} ~Transaction() {} + // Item transactions void resetItem(ItemID id, const PayloadPointer& payload); void removeItem(ItemID id); @@ -44,14 +45,22 @@ public: void updateItem(ItemID id, const UpdateFunctorPointer& functor); void updateItem(ItemID id) { updateItem(id, nullptr); } + // Selection transactions + void resetSelection(const Selection& selection); + void merge(const Transaction& transaction); + // Checkers if there is work to do when processing the transaction + bool touchTransactions() const { return !_resetSelections.empty(); } + ItemIDs _resetItems; Payloads _resetPayloads; ItemIDs _removedItems; ItemIDs _updatedItems; UpdateFunctors _updateFunctors; + Selections _resetSelections; + protected: }; typedef std::queue TransactionQueue; @@ -82,6 +91,10 @@ public: // Process the pending transactions queued void processTransactionQueue(); + // Access a particular selection (empty if doesn't exist) + // Thread safe + Selection getSelection(const Selection::Name& name) const; + // This next call are NOT threadsafe, you have to call them from the correct thread to avoid any potential issues // Access a particular item form its ID @@ -117,9 +130,15 @@ protected: // The Selection map - std::mutex _selectionsMutex; + mutable std::mutex _selectionsMutex; // mutable so it can be used in the thread safe getSelection const method SelectionMap _selections; + void resetSelections(const Selections& selections); + // More actions coming to selections soon: + // void removeFromSelection(const Selection& selection); + // void appendToSelection(const Selection& selection); + // void mergeWithSelection(const Selection& selection); + friend class Engine; }; diff --git a/libraries/render/src/render/Selection.cpp b/libraries/render/src/render/Selection.cpp index ba72953455..0501a1f80d 100644 --- a/libraries/render/src/render/Selection.cpp +++ b/libraries/render/src/render/Selection.cpp @@ -14,11 +14,42 @@ using namespace render; -Selection::Selection(const std::string& name, const ItemIDs items) : + +Selection::Selection() : +_name(), +_items() +{ +} + +Selection::Selection(const Selection& selection) : +_name(selection._name), +_items(selection._items) +{ +} + +Selection& Selection::operator= (const Selection& selection) { + _name = (selection._name); + _items = (selection._items); + return (*this); +} + +Selection::Selection(Selection&& selection) : +_name(selection._name), +_items(selection._items) +{ +} + + +Selection& Selection::operator= (Selection&& selection) { + _name = (selection._name); + _items = (selection._items); + return (*this); +} + +Selection::Selection(const Name& name, const ItemIDs& items) : _name(name), _items(items) { - } Selection::~Selection() { diff --git a/libraries/render/src/render/Selection.h b/libraries/render/src/render/Selection.h index 64bfb2455f..7623e53910 100644 --- a/libraries/render/src/render/Selection.h +++ b/libraries/render/src/render/Selection.h @@ -18,21 +18,28 @@ namespace render { class Selection { public: + using Name = std::string; - Selection(const std::string& name, const ItemIDs items); ~Selection(); + Selection(); + Selection(const Selection& selection); + Selection& operator= (const Selection& selection); + Selection(Selection&& selection); + Selection& operator= (Selection&& selection); - const std::string& getName() const { return _name; } + Selection(const Name& name, const ItemIDs& items); + + const Name& getName() const { return _name; } const ItemIDs& getItems() const { return _items; } protected: - const std::string _name; + Name _name; ItemIDs _items; }; using Selections = std::vector; - using SelectionMap = std::map; + using SelectionMap = std::map; } From 6fc965072c8a8fc1677b4598941a06397871fb21 Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 6 Apr 2017 15:19:55 -0700 Subject: [PATCH 09/27] Adding the Selection, and not the Tag concept fro real, and beeing able to reset it from the Transaction and simply communicating the ranked zones to the engine through a selection, ready to be used by the ZOneREnderer --- .../src/EntityTreeRenderer.cpp | 29 +++++++++++ .../src/EntityTreeRenderer.h | 1 + .../src/RenderableZoneEntityItem.h | 2 + .../render-utils/src/RenderDeferredTask.cpp | 1 + libraries/render-utils/src/ZoneRenderer.cpp | 25 ++++++++++ libraries/render-utils/src/ZoneRenderer.h | 48 +++++++++++++++++++ libraries/render/src/render/Selection.cpp | 8 ++-- libraries/render/src/render/Selection.h | 4 +- 8 files changed, 112 insertions(+), 6 deletions(-) create mode 100644 libraries/render-utils/src/ZoneRenderer.cpp create mode 100644 libraries/render-utils/src/ZoneRenderer.h diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index fd5e07918e..176ba9a4d8 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -43,6 +43,8 @@ #include "AddressManager.h" #include +#include "ZoneRenderer.h" + EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState, AbstractScriptingServicesInterface* scriptingServices) : _wantScripts(wantScripts), @@ -266,6 +268,9 @@ bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVectorgetAvatarPosition() + glm::vec3((float)TREE_SCALE); } +bool EntityTreeRenderer::applyLayeredZones() { + // from the list of zones we are going to build a selection list the Render Item corresponding to the zones + // in the expected layered order and update the scene with it + auto scene = _viewState->getMain3DScene(); + if (scene) { + render::Transaction transaction; + render::ItemIDs list; + + for (auto& zone : _layeredZones) { + auto id = std::dynamic_pointer_cast(zone.zone)->getRenderItemID(); + list.push_back(id); + } + render::Selection selection("RankedZones", list); + transaction.resetSelection(selection); + + scene->enqueueTransaction(transaction); + } else { + qCWarning(entitiesrenderer) << "EntityTreeRenderer::applyLayeredZones(), Unexpected null scene, possibly during application shutdown"; + } + + +} + + bool EntityTreeRenderer::applyZoneAndHasSkybox(const std::shared_ptr& zone) { auto textureCache = DependencyManager::get(); auto scene = DependencyManager::get(); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.h b/libraries/entities-renderer/src/EntityTreeRenderer.h index 753f25310c..ec9f707962 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.h +++ b/libraries/entities-renderer/src/EntityTreeRenderer.h @@ -150,6 +150,7 @@ private: bool applyZoneAndHasSkybox(const std::shared_ptr& zone); bool layerZoneAndHasSkybox(const std::shared_ptr& zone); bool applySkyboxAndHasAmbient(); + bool applyLayeredZones(); void checkAndCallPreload(const EntityItemID& entityID, const bool reload = false, const bool unloadFirst = false); diff --git a/libraries/entities-renderer/src/RenderableZoneEntityItem.h b/libraries/entities-renderer/src/RenderableZoneEntityItem.h index bbb7ed0c01..d86a22509b 100644 --- a/libraries/entities-renderer/src/RenderableZoneEntityItem.h +++ b/libraries/entities-renderer/src/RenderableZoneEntityItem.h @@ -41,6 +41,8 @@ public: virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override; virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::Transaction& transaction) override; + render::ItemID getRenderItemID() const { return _myMetaItem; } + private: virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); } virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 22aa95090c..79e5bc9aca 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -33,6 +33,7 @@ #include "FramebufferCache.h" #include "HitEffect.h" #include "TextureCache.h" +#include "ZoneRenderer.h" #include "AmbientOcclusionEffect.h" #include "AntialiasingEffect.h" diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp new file mode 100644 index 0000000000..7de12cf5a8 --- /dev/null +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -0,0 +1,25 @@ +// +// ZoneRenderer.cpp +// render/src/render-utils +// +// Created by Sam Gateau on 4/4/2017. +// Copyright 2017 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 +// +#include "ZoneRenderer.h" + +const render::Selection::Name ZoneRenderer::ZONES_SELECTION { "RankedZones" }; + + +void ZoneRenderer::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) { + auto& scene = sceneContext->_scene; + RenderArgs* args = renderContext->args; + + auto zones = scene->getSelection(ZONES_SELECTION); + + +} + + diff --git a/libraries/render-utils/src/ZoneRenderer.h b/libraries/render-utils/src/ZoneRenderer.h new file mode 100644 index 0000000000..619020478a --- /dev/null +++ b/libraries/render-utils/src/ZoneRenderer.h @@ -0,0 +1,48 @@ +// +// ZoneRenderer.h +// render/src/render-utils +// +// Created by Sam Gateau on 4/4/2017. +// Copyright 2017 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 +// + +#ifndef hifi_ZoneRenderer_h +#define hifi_ZoneRenderer_h + +#include "render/Engine.h" + +class ZoneRendererConfig : public render::Job::Config { + Q_OBJECT + Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) +public: + + int maxDrawn { -1 }; + +signals: + void dirty(); + +protected: +}; + +class ZoneRenderer { +public: + + static const render::Selection::Name ZONES_SELECTION; + + using Inputs = render::ItemBounds; + using Config = ZoneRendererConfig; + using JobModel = render::Job::ModelI; + + ZoneRenderer() {} + + void configure(const Config& config) { _maxDrawn = config.maxDrawn; } + void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs); + +protected: + int _maxDrawn; // initialized by Config +}; + +#endif \ No newline at end of file diff --git a/libraries/render/src/render/Selection.cpp b/libraries/render/src/render/Selection.cpp index 0501a1f80d..9ffd34d4b5 100644 --- a/libraries/render/src/render/Selection.cpp +++ b/libraries/render/src/render/Selection.cpp @@ -15,6 +15,10 @@ using namespace render; +Selection::~Selection() { + +} + Selection::Selection() : _name(), _items() @@ -52,7 +56,3 @@ Selection::Selection(const Name& name, const ItemIDs& items) : { } -Selection::~Selection() { - -} - diff --git a/libraries/render/src/render/Selection.h b/libraries/render/src/render/Selection.h index 7623e53910..71c15acf11 100644 --- a/libraries/render/src/render/Selection.h +++ b/libraries/render/src/render/Selection.h @@ -23,9 +23,9 @@ namespace render { ~Selection(); Selection(); Selection(const Selection& selection); - Selection& operator= (const Selection& selection); + Selection& operator = (const Selection& selection); Selection(Selection&& selection); - Selection& operator= (Selection&& selection); + Selection& operator = (Selection&& selection); Selection(const Name& name, const ItemIDs& items); From cb94e1009d303282a80ae7e54cb10b4a899d45ca Mon Sep 17 00:00:00 2001 From: samcake Date: Thu, 6 Apr 2017 18:10:28 -0700 Subject: [PATCH 10/27] Adding a job... --- libraries/render-utils/src/RenderDeferredTask.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 79e5bc9aca..d587dd0342 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -184,6 +184,7 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying(); addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); + addJob("ZoneRenderer", opaques); // Scene Octree Debugging job { From e6844f4294ee33a644f798a0ec29afa7e6fc6ed3 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 7 Apr 2017 18:35:27 -0700 Subject: [PATCH 11/27] Cleaning up the basic jobs of render --- .../render-utils/src/RenderDeferredTask.cpp | 5 +- libraries/render-utils/src/ZoneRenderer.cpp | 14 +- libraries/render-utils/src/ZoneRenderer.h | 8 +- libraries/render/src/render/CullTask.cpp | 18 --- libraries/render/src/render/CullTask.h | 79 ---------- libraries/render/src/render/FilterTask.cpp | 83 +++++++++++ libraries/render/src/render/FilterTask.h | 136 ++++++++++++++++++ .../src/render/RenderFetchCullSortTask.cpp | 13 +- libraries/render/src/render/Selection.cpp | 8 ++ libraries/render/src/render/Selection.h | 3 + 10 files changed, 253 insertions(+), 114 deletions(-) create mode 100644 libraries/render/src/render/FilterTask.cpp create mode 100644 libraries/render/src/render/FilterTask.h diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index d587dd0342..97b7568546 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -66,7 +67,7 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { // Filter the non antialiaased overlays const int LAYER_NO_AA = 3; - const auto nonAAOverlays = addJob("Filter2DWebOverlays", overlayOpaques, LAYER_NO_AA); + const auto nonAAOverlays = addJob("Filter2DWebOverlays", overlayOpaques, LAYER_NO_AA); // Prepare deferred, generate the shared Deferred Frame Transform const auto deferredFrameTransform = addJob("DeferredFrameTransform"); @@ -184,7 +185,7 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying(); addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); - addJob("ZoneRenderer", opaques); + addJob("ZoneRenderer", opaques); // Scene Octree Debugging job { diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index 7de12cf5a8..12252743a7 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -10,15 +10,19 @@ // #include "ZoneRenderer.h" -const render::Selection::Name ZoneRenderer::ZONES_SELECTION { "RankedZones" }; +#include +#include +using namespace render; -void ZoneRenderer::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs) { - auto& scene = sceneContext->_scene; - RenderArgs* args = renderContext->args; +const Selection::Name ZoneRendererTask::ZONES_SELECTION { "RankedZones" }; - auto zones = scene->getSelection(ZONES_SELECTION); +ZoneRendererTask::ZoneRendererTask(const Inputs& inputs) { + const auto zoneItems = addJob("FilterZones", inputs, ZONES_SELECTION); + + // just draw them... + addJob("DrawZones", zoneItems); } diff --git a/libraries/render-utils/src/ZoneRenderer.h b/libraries/render-utils/src/ZoneRenderer.h index 619020478a..941a99772d 100644 --- a/libraries/render-utils/src/ZoneRenderer.h +++ b/libraries/render-utils/src/ZoneRenderer.h @@ -27,19 +27,19 @@ signals: protected: }; -class ZoneRenderer { +class ZoneRendererTask : public render::Task { public: static const render::Selection::Name ZONES_SELECTION; + using Inputs = render::ItemBounds; using Config = ZoneRendererConfig; - using JobModel = render::Job::ModelI; + using JobModel = Model; - ZoneRenderer() {} + ZoneRendererTask(const Inputs& inputs); void configure(const Config& config) { _maxDrawn = config.maxDrawn; } - void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const Inputs& inputs); protected: int _maxDrawn; // initialized by Config diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index 42f95f458f..e4ba5af13f 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -16,8 +16,6 @@ #include #include -#include -#include using namespace render; @@ -306,19 +304,3 @@ void CullSpatialSelection::run(const SceneContextPointer& sceneContext, const Re std::static_pointer_cast(renderContext->jobConfig)->numItems = (int)outItems.size(); } - - -void FilterItemLayer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { - auto& scene = sceneContext->_scene; - - // Clear previous values - outItems.clear(); - - // For each item, filter it into one bucket - for (auto itemBound : inItems) { - auto& item = scene->getItem(itemBound.id); - if (item.getLayer() == _keepLayer) { - outItems.emplace_back(itemBound); - } - } -} \ No newline at end of file diff --git a/libraries/render/src/render/CullTask.h b/libraries/render/src/render/CullTask.h index f613faa2e6..243b16e733 100644 --- a/libraries/render/src/render/CullTask.h +++ b/libraries/render/src/render/CullTask.h @@ -109,85 +109,6 @@ namespace render { void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemSpatialTree::ItemSelection& inSelection, ItemBounds& outItems); }; - class FilterItemSelectionConfig : public Job::Config { - Q_OBJECT - Q_PROPERTY(int numItems READ getNumItems) - public: - int numItems{ 0 }; - int getNumItems() { return numItems; } - }; - - class FilterItemSelection { - public: - using Config = FilterItemSelectionConfig; - using JobModel = Job::ModelIO; - - FilterItemSelection() {} - FilterItemSelection(const ItemFilter& filter) : - _filter(filter) {} - - ItemFilter _filter{ ItemFilter::Builder::opaqueShape().withoutLayered() }; - - void configure(const Config& config); - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); - }; - - class MultiFilterItemConfig : public Job::Config { - Q_OBJECT - Q_PROPERTY(int numItems READ getNumItems) - public: - int numItems{ 0 }; - int getNumItems() { return numItems; } - }; - - template - class MultiFilterItem { - public: - using ItemFilterArray = std::array; - using ItemBoundsArray = VaryingArray; - using Config = MultiFilterItemConfig; - using JobModel = Job::ModelIO; - - MultiFilterItem() {} - MultiFilterItem(const ItemFilterArray& filters) : - _filters(filters) {} - - ItemFilterArray _filters; - - void configure(const Config& config) {} - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBoundsArray& outItems) { - auto& scene = sceneContext->_scene; - - // Clear previous values - for (size_t i = 0; i < NUM_FILTERS; i++) { - outItems[i].template edit().clear(); - } - - // For each item, filter it into one bucket - for (auto itemBound : inItems) { - auto& item = scene->getItem(itemBound.id); - auto itemKey = item.getKey(); - for (size_t i = 0; i < NUM_FILTERS; i++) { - if (_filters[i].test(itemKey)) { - outItems[i].template edit().emplace_back(itemBound); - } - } - } - } - }; - - class FilterItemLayer { - public: - using JobModel = Job::ModelIO; - - FilterItemLayer() {} - FilterItemLayer(int keepLayer) : - _keepLayer(keepLayer) {} - - int _keepLayer { 0 }; - - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); - }; } #endif // hifi_render_CullTask_h; \ No newline at end of file diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp new file mode 100644 index 0000000000..1c044d2db4 --- /dev/null +++ b/libraries/render/src/render/FilterTask.cpp @@ -0,0 +1,83 @@ +// +// FilterTask.cpp +// render/src/render +// +// Created by Sam Gateau on 2/2/16. +// Copyright 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 +// + +#include "FilterTask.h" + +#include +#include + +#include +#include +#include +#include + +using namespace render; + +void FilterLayeredItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { + auto& scene = sceneContext->_scene; + + // Clear previous values + outItems.clear(); + + // For each item, filter it into one bucket + for (auto itemBound : inItems) { + auto& item = scene->getItem(itemBound.id); + if (item.getLayer() == _keepLayer) { + outItems.emplace_back(itemBound); + } + } +} + +void SliceItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { + auto& scene = sceneContext->_scene; + + // Now we have a selection of items to render + outItems.clear(); + std::static_pointer_cast(renderContext->jobConfig)->setNumItems((int)inItems.size()); + + if (_rangeOffset < 0) return; + + int maxItemNum = std::min(_rangeOffset + _rangeLength, (int)inItems.size()); + + + for (int i = _rangeOffset; i < maxItemNum; i++) { + outItems.emplace_back(inItems[i]); + } + +} + +void SelectItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { + auto& scene = sceneContext->_scene; + + auto selection = scene->getSelection(_name); + const auto& selectedItems = selection.getItems(); + if (!selectedItems.empty()) { + for (auto src : inItems) { + if (selection.contains(src.id)) { + outItems.emplace_back(src); + } + } + } +} + +void MetaToSubItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemIDs& outItems) { + auto& scene = sceneContext->_scene; + + // Now we have a selection of items to render + outItems.clear(); + + for (auto idBound : inItems) { + auto& item = scene->getItem(idBound.id); + + item.fetchMetaSubItems(outItems); + } +} + diff --git a/libraries/render/src/render/FilterTask.h b/libraries/render/src/render/FilterTask.h new file mode 100644 index 0000000000..46a9ef25bd --- /dev/null +++ b/libraries/render/src/render/FilterTask.h @@ -0,0 +1,136 @@ +// +// FilterTask.h +// render/src/render +// +// Created by Sam Gateau on 2/2/16. +// Copyright 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 +// + +#ifndef hifi_render_FilterTask_h +#define hifi_render_FilterTask_h + +#include "Engine.h" +#include "ViewFrustum.h" + +namespace render { + + class MultiFilterItemsConfig : public Job::Config { + Q_OBJECT + Q_PROPERTY(int numItems READ getNumItems) + public: + int numItems{ 0 }; + int getNumItems() { return numItems; } + }; + + // Filter inbound of items into multiple buckets defined from the job's Filter array + template + class MultiFilterItems { + public: + using ItemFilterArray = std::array; + using ItemBoundsArray = VaryingArray; + using Config = MultiFilterItemsConfig; + using JobModel = Job::ModelIO; + + MultiFilterItems() {} + MultiFilterItems(const ItemFilterArray& filters) : + _filters(filters) {} + + ItemFilterArray _filters; + + void configure(const Config& config) {} + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBoundsArray& outItems) { + auto& scene = sceneContext->_scene; + + // Clear previous values + for (size_t i = 0; i < NUM_FILTERS; i++) { + outItems[i].template edit().clear(); + } + + // For each item, filter it into one bucket + for (auto itemBound : inItems) { + auto& item = scene->getItem(itemBound.id); + auto itemKey = item.getKey(); + for (size_t i = 0; i < NUM_FILTERS; i++) { + if (_filters[i].test(itemKey)) { + outItems[i].template edit().emplace_back(itemBound); + } + } + } + } + }; + + // Filter the items belonging to the job's keep layer + class FilterLayeredItems { + public: + using JobModel = Job::ModelIO; + + FilterLayeredItems() {} + FilterLayeredItems(int keepLayer) : + _keepLayer(keepLayer) {} + + int _keepLayer { 0 }; + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); + }; + + // SliceItems job config defining the slice range + class SliceItemsConfig : public Job::Config { + Q_OBJECT + Q_PROPERTY(int rangeOffset MEMBER rangeOffset) + Q_PROPERTY(int rangeLength MEMBER rangeLength) + Q_PROPERTY(int numItems READ getNumItems NOTIFY dirty()) + int numItems { 0 }; + public: + int rangeOffset{ -1 }; + int rangeLength{ 1 }; + int getNumItems() { return numItems; } + void setNumItems(int n) { numItems = n; emit dirty(); } + signals: + void dirty(); + }; + + // Keep items in the job slice (defined from config) + class SliceItems { + public: + using Config = SliceItemsConfig; + using JobModel = Job::ModelIO; + + SliceItems() {} + int _rangeOffset{ -1 }; + int _rangeLength{ 1 }; + + void configure(const Config& config) { + _rangeOffset = config.rangeOffset; + _rangeLength = config.rangeLength; + } + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); + }; + + // Keep items belonging to the job selection + class SelectItems { + public: + using JobModel = Job::ModelIO; + + std::string _name; + SelectItems(const Selection::Name& name) : _name(name) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); + }; + + // From meta-Items, generate the sub-items + class MetaToSubItems { + public: + using JobModel = Job::ModelIO; + + MetaToSubItems() {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemIDs& outItems); + }; + +} + +#endif // hifi_render_FilterTask_h; \ No newline at end of file diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 69c415dffd..671cdfff8f 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -12,6 +12,7 @@ #include "RenderFetchCullSortTask.h" #include "CullTask.h" +#include "FilterTask.h" #include "SortTask.h" using namespace render; @@ -36,23 +37,23 @@ RenderFetchCullSortTask::RenderFetchCullSortTask(CullFunctor cullFunctor) { const int LIGHT_BUCKET = 2; const int META_BUCKET = 3; const int BACKGROUND_BUCKET = 2; - MultiFilterItem::ItemFilterArray spatialFilters = { { + MultiFilterItems::ItemFilterArray spatialFilters = { { ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::transparentShape(), ItemFilter::Builder::light(), ItemFilter::Builder::meta() } }; - MultiFilterItem::ItemFilterArray nonspatialFilters = { { + MultiFilterItems::ItemFilterArray nonspatialFilters = { { ItemFilter::Builder::opaqueShape(), ItemFilter::Builder::transparentShape(), ItemFilter::Builder::background() } }; const auto filteredSpatialBuckets = - addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters) - .get::ItemBoundsArray>(); + addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters) + .get::ItemBoundsArray>(); const auto filteredNonspatialBuckets = - addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters) - .get::ItemBoundsArray>(); + addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters) + .get::ItemBoundsArray>(); // Extract opaques / transparents / lights / overlays const auto opaques = addJob("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]); diff --git a/libraries/render/src/render/Selection.cpp b/libraries/render/src/render/Selection.cpp index 9ffd34d4b5..5ac0f415f4 100644 --- a/libraries/render/src/render/Selection.cpp +++ b/libraries/render/src/render/Selection.cpp @@ -56,3 +56,11 @@ Selection::Selection(const Name& name, const ItemIDs& items) : { } +bool Selection::contains(ItemID id) const { + for (auto selected : _items) { + if (selected == id) { + return true; + } + } + return false; +} \ No newline at end of file diff --git a/libraries/render/src/render/Selection.h b/libraries/render/src/render/Selection.h index 71c15acf11..6c5f6aab10 100644 --- a/libraries/render/src/render/Selection.h +++ b/libraries/render/src/render/Selection.h @@ -33,6 +33,9 @@ namespace render { const ItemIDs& getItems() const { return _items; } + bool isEmpty() const { return _items.empty(); } + bool contains(ItemID id) const; + protected: Name _name; ItemIDs _items; From b65448bcbe76ad8e39c3a492fb0a38d1540f476b Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Sun, 9 Apr 2017 11:08:35 -0700 Subject: [PATCH 12/27] Trying to improve the Job/Task classes and testing it with the ZoneRenderer --- interface/src/Application.cpp | 4 +- .../src/EntityTreeRenderer.cpp | 2 +- .../render-utils/src/RenderDeferredTask.cpp | 84 ++++++++++--------- .../render-utils/src/RenderDeferredTask.h | 7 +- .../render-utils/src/RenderForwardTask.cpp | 16 ++-- .../render-utils/src/RenderForwardTask.h | 7 +- .../render-utils/src/RenderShadowTask.cpp | 16 ++-- libraries/render-utils/src/RenderShadowTask.h | 5 +- libraries/render-utils/src/ZoneRenderer.cpp | 8 +- libraries/render-utils/src/ZoneRenderer.h | 6 +- libraries/render/src/render/Engine.cpp | 3 + libraries/render/src/render/Engine.h | 1 + libraries/render/src/render/FilterTask.cpp | 1 + .../src/render/RenderFetchCullSortTask.cpp | 22 ++--- .../src/render/RenderFetchCullSortTask.h | 6 +- libraries/render/src/render/Task.h | 47 +++++++---- .../utilities/render/debugDeferredLighting.js | 2 +- .../utilities/render/deferredLighting.qml | 5 ++ tests/render-perf/src/main.cpp | 4 +- 19 files changed, 143 insertions(+), 103 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 342d325f58..778df09588 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1880,9 +1880,9 @@ void Application::initializeGL() { assert(items.canCast()); static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD"; if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) { - _renderEngine->addJob("Forward", items.get()); + _renderEngine->addJob("Forward", items); } else { - _renderEngine->addJob("RenderDeferredTask", items.get()); + _renderEngine->addJob("RenderDeferredTask", items); } _renderEngine->load(); _renderEngine->registerScene(_main3DScene); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 176ba9a4d8..63684dcf0f 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -368,7 +368,7 @@ bool EntityTreeRenderer::applyLayeredZones() { qCWarning(entitiesrenderer) << "EntityTreeRenderer::applyLayeredZones(), Unexpected null scene, possibly during application shutdown"; } - + return true; } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 97b7568546..4e9203ad4f 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -50,7 +50,9 @@ using namespace render; extern void initOverlay3DPipelines(render::ShapePlumber& plumber); extern void initDeferredPipelines(render::ShapePlumber& plumber); -RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { +void RenderDeferredTask::build(render::Task& task, const render::Varying& input, render::Varying& output) { + auto items = input.get(); + // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); initDeferredPipelines(*shapePlumber); @@ -67,130 +69,130 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { // Filter the non antialiaased overlays const int LAYER_NO_AA = 3; - const auto nonAAOverlays = addJob("Filter2DWebOverlays", overlayOpaques, LAYER_NO_AA); + const auto nonAAOverlays = task.addJob("Filter2DWebOverlays", overlayOpaques, LAYER_NO_AA); // Prepare deferred, generate the shared Deferred Frame Transform - const auto deferredFrameTransform = addJob("DeferredFrameTransform"); - const auto lightingModel = addJob("LightingModel"); + const auto deferredFrameTransform = task.addJob("DeferredFrameTransform"); + const auto lightingModel = task.addJob("LightingModel"); // GPU jobs: Start preparing the primary, deferred and lighting buffer - const auto primaryFramebuffer = addJob("PreparePrimaryBuffer"); + const auto primaryFramebuffer = task.addJob("PreparePrimaryBuffer"); - const auto opaqueRangeTimer = addJob("BeginOpaqueRangeTimer", "DrawOpaques"); + const auto opaqueRangeTimer = task.addJob("BeginOpaqueRangeTimer", "DrawOpaques"); const auto prepareDeferredInputs = PrepareDeferred::Inputs(primaryFramebuffer, lightingModel).hasVarying(); - const auto prepareDeferredOutputs = addJob("PrepareDeferred", prepareDeferredInputs); + const auto prepareDeferredOutputs = task.addJob("PrepareDeferred", prepareDeferredInputs); const auto deferredFramebuffer = prepareDeferredOutputs.getN(0); const auto lightingFramebuffer = prepareDeferredOutputs.getN(1); // Render opaque objects in DeferredBuffer const auto opaqueInputs = DrawStateSortDeferred::Inputs(opaques, lightingModel).hasVarying(); - addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); + task.addJob("DrawOpaqueDeferred", opaqueInputs, shapePlumber); // Once opaque is all rendered create stencil background - addJob("DrawOpaqueStencil", deferredFramebuffer); + task.addJob("DrawOpaqueStencil", deferredFramebuffer); - addJob("OpaqueRangeTimer", opaqueRangeTimer); + task.addJob("OpaqueRangeTimer", opaqueRangeTimer); // Opaque all rendered // Linear Depth Pass const auto linearDepthPassInputs = LinearDepthPass::Inputs(deferredFrameTransform, deferredFramebuffer).hasVarying(); - const auto linearDepthPassOutputs = addJob("LinearDepth", linearDepthPassInputs); + const auto linearDepthPassOutputs = task.addJob("LinearDepth", linearDepthPassInputs); const auto linearDepthTarget = linearDepthPassOutputs.getN(0); // Curvature pass const auto surfaceGeometryPassInputs = SurfaceGeometryPass::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying(); - const auto surfaceGeometryPassOutputs = addJob("SurfaceGeometry", surfaceGeometryPassInputs); + const auto surfaceGeometryPassOutputs = task.addJob("SurfaceGeometry", surfaceGeometryPassInputs); const auto surfaceGeometryFramebuffer = surfaceGeometryPassOutputs.getN(0); const auto curvatureFramebuffer = surfaceGeometryPassOutputs.getN(1); const auto midCurvatureNormalFramebuffer = surfaceGeometryPassOutputs.getN(2); const auto lowCurvatureNormalFramebuffer = surfaceGeometryPassOutputs.getN(3); // Simply update the scattering resource - const auto scatteringResource = addJob("Scattering"); + const auto scatteringResource = task.addJob("Scattering"); // AO job const auto ambientOcclusionInputs = AmbientOcclusionEffect::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget).hasVarying(); - const auto ambientOcclusionOutputs = addJob("AmbientOcclusion", ambientOcclusionInputs); + const auto ambientOcclusionOutputs = task.addJob("AmbientOcclusion", ambientOcclusionInputs); const auto ambientOcclusionFramebuffer = ambientOcclusionOutputs.getN(0); const auto ambientOcclusionUniforms = ambientOcclusionOutputs.getN(1); // Draw Lights just add the lights to the current list of lights to deal with. NOt really gpu job for now. - addJob("DrawLight", lights); + task.addJob("DrawLight", lights); // Light Clustering // Create the cluster grid of lights, cpu job for now const auto lightClusteringPassInputs = LightClusteringPass::Inputs(deferredFrameTransform, lightingModel, linearDepthTarget).hasVarying(); - const auto lightClusters = addJob("LightClustering", lightClusteringPassInputs); + const auto lightClusters = task.addJob("LightClustering", lightClusteringPassInputs); // DeferredBuffer is complete, now let's shade it into the LightingBuffer const auto deferredLightingInputs = RenderDeferred::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource, lightClusters).hasVarying(); - addJob("RenderDeferred", deferredLightingInputs); + task.addJob("RenderDeferred", deferredLightingInputs); // Use Stencil and draw background in Lighting buffer to complete filling in the opaque const auto backgroundInputs = DrawBackgroundDeferred::Inputs(background, lightingModel).hasVarying(); - addJob("DrawBackgroundDeferred", backgroundInputs); + task.addJob("DrawBackgroundDeferred", backgroundInputs); // Render transparent objects forward in LightingBuffer const auto transparentsInputs = DrawDeferred::Inputs(transparents, lightingModel).hasVarying(); - addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); + task.addJob("DrawTransparentDeferred", transparentsInputs, shapePlumber); // LIght Cluster Grid Debuging job { const auto debugLightClustersInputs = DebugLightClusters::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, linearDepthTarget, lightClusters).hasVarying(); - addJob("DebugLightClusters", debugLightClustersInputs); + task.addJob("DebugLightClusters", debugLightClustersInputs); } - const auto toneAndPostRangeTimer = addJob("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing"); + const auto toneAndPostRangeTimer = task.addJob("BeginToneAndPostRangeTimer", "PostToneOverlaysAntialiasing"); // Lighting Buffer ready for tone mapping const auto toneMappingInputs = render::Varying(ToneMappingDeferred::Inputs(lightingFramebuffer, primaryFramebuffer)); - addJob("ToneMapping", toneMappingInputs); + task.addJob("ToneMapping", toneMappingInputs); { // DEbug the bounds of the rendered items, still look at the zbuffer - addJob("DrawMetaBounds", metas); - addJob("DrawOpaqueBounds", opaques); - addJob("DrawTransparentBounds", transparents); + task.addJob("DrawMetaBounds", metas); + task.addJob("DrawOpaqueBounds", opaques); + task.addJob("DrawTransparentBounds", transparents); + + task.addJob("ZoneRenderer", opaques); } // Overlays const auto overlayOpaquesInputs = DrawOverlay3D::Inputs(overlayOpaques, lightingModel).hasVarying(); const auto overlayTransparentsInputs = DrawOverlay3D::Inputs(overlayTransparents, lightingModel).hasVarying(); - addJob("DrawOverlay3DOpaque", overlayOpaquesInputs, true); - addJob("DrawOverlay3DTransparent", overlayTransparentsInputs, false); + task.addJob("DrawOverlay3DOpaque", overlayOpaquesInputs, true); + task.addJob("DrawOverlay3DTransparent", overlayTransparentsInputs, false); { // DEbug the bounds of the rendered OVERLAY items, still look at the zbuffer - addJob("DrawOverlayOpaqueBounds", overlayOpaques); - addJob("DrawOverlayTransparentBounds", overlayTransparents); + task.addJob("DrawOverlayOpaqueBounds", overlayOpaques); + task.addJob("DrawOverlayTransparentBounds", overlayTransparents); } // Debugging stages { // Debugging Deferred buffer job const auto debugFramebuffers = render::Varying(DebugDeferredBuffer::Inputs(deferredFramebuffer, linearDepthTarget, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer)); - addJob("DebugDeferredBuffer", debugFramebuffers); + task.addJob("DebugDeferredBuffer", debugFramebuffers); const auto debugSubsurfaceScatteringInputs = DebugSubsurfaceScattering::Inputs(deferredFrameTransform, deferredFramebuffer, lightingModel, surfaceGeometryFramebuffer, ambientOcclusionFramebuffer, scatteringResource).hasVarying(); - addJob("DebugScattering", debugSubsurfaceScatteringInputs); + task.addJob("DebugScattering", debugSubsurfaceScatteringInputs); const auto debugAmbientOcclusionInputs = DebugAmbientOcclusion::Inputs(deferredFrameTransform, deferredFramebuffer, linearDepthTarget, ambientOcclusionUniforms).hasVarying(); - addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); - - addJob("ZoneRenderer", opaques); + task.addJob("DebugAmbientOcclusion", debugAmbientOcclusionInputs); // Scene Octree Debugging job { - addJob("DrawSceneOctree", spatialSelection); - addJob("DrawItemSelection", spatialSelection); + task.addJob("DrawSceneOctree", spatialSelection); + task.addJob("DrawItemSelection", spatialSelection); } // Status icon rendering job @@ -198,22 +200,22 @@ RenderDeferredTask::RenderDeferredTask(RenderFetchCullSortTask::Output items) { // Grab a texture map representing the different status icons and assign that to the drawStatsuJob auto iconMapPath = PathUtils::resourcesPath() + "icons/statusIconAtlas.svg"; auto statusIconMap = DependencyManager::get()->getImageTexture(iconMapPath, NetworkTexture::STRICT_TEXTURE); - addJob("DrawStatus", opaques, DrawStatus(statusIconMap)); + task.addJob("DrawStatus", opaques, DrawStatus(statusIconMap)); } } // AA job to be revisited - addJob("Antialiasing", primaryFramebuffer); + task.addJob("Antialiasing", primaryFramebuffer); // Draw 2DWeb non AA const auto nonAAOverlaysInputs = DrawOverlay3D::Inputs(nonAAOverlays, lightingModel).hasVarying(); - addJob("Draw2DWebSurfaces", nonAAOverlaysInputs, false); + task.addJob("Draw2DWebSurfaces", nonAAOverlaysInputs, false); - addJob("ToneAndPostRangeTimer", toneAndPostRangeTimer); + task.addJob("ToneAndPostRangeTimer", toneAndPostRangeTimer); // Blit! - addJob("Blit", primaryFramebuffer); + task.addJob("Blit", primaryFramebuffer); } void BeginGPURangeTimer::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, gpu::RangeTimerPointer& timer) { diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 8a95447e67..9ad61b8f1e 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -194,9 +194,12 @@ public: class RenderDeferredTask : public render::Task { public: - using JobModel = Model; + using Input = RenderFetchCullSortTask::Output; + using JobModel = render::Task::ModelI; - RenderDeferredTask(RenderFetchCullSortTask::Output items); + RenderDeferredTask() {} + + void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs); }; #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 49090c2f5f..630146c698 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -29,7 +29,9 @@ using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); -RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { +void RenderForwardTask::build(render::Task& task, const render::Varying& input, render::Varying& output) { + auto items = input.get(); + // Prepare the ShapePipelines ShapePlumberPointer shapePlumber = std::make_shared(); initForwardPipelines(*shapePlumber); @@ -44,17 +46,17 @@ RenderForwardTask::RenderForwardTask(RenderFetchCullSortTask::Output items) { const auto background = items[RenderFetchCullSortTask::BACKGROUND]; const auto spatialSelection = items[RenderFetchCullSortTask::SPATIAL_SELECTION]; - const auto framebuffer = addJob("PrepareFramebuffer"); + const auto framebuffer = task.addJob("PrepareFramebuffer"); - addJob("DrawOpaques", opaques, shapePlumber); - addJob("Stencil"); - addJob("DrawBackground", background); + task.addJob("DrawOpaques", opaques, shapePlumber); + task.addJob("Stencil"); + task.addJob("DrawBackground", background); // Bounds do not draw on stencil buffer, so they must come last - addJob("DrawBounds", opaques); + task.addJob("DrawBounds", opaques); // Blit! - addJob("Blit", framebuffer); + task.addJob("Blit", framebuffer); } void PrepareFramebuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 62cbca4382..3fcf1b398f 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -18,9 +18,12 @@ class RenderForwardTask : public render::Task { public: - using JobModel = Model; + using Input = RenderFetchCullSortTask::Output; + using JobModel = render::Task::ModelI; - RenderForwardTask(RenderFetchCullSortTask::Output items); + RenderForwardTask() {} + + void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs); }; class PrepareFramebuffer { diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index eb46b8f46e..04e054c921 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -90,7 +90,7 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const }); } -RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) { +void RenderShadowTask::build(render::Task& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) { cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; // Prepare the ShapePipeline @@ -115,22 +115,22 @@ RenderShadowTask::RenderShadowTask(CullFunctor cullFunctor) { skinProgram, state); } - const auto cachedMode = addJob("Setup"); + const auto cachedMode = task.addJob("Setup"); // CPU jobs: // Fetch and cull the items from the scene auto shadowFilter = ItemFilter::Builder::visibleWorldItems().withTypeShape().withOpaque().withoutLayered(); - const auto shadowSelection = addJob("FetchShadowSelection", shadowFilter); - const auto culledShadowSelection = addJob("CullShadowSelection", shadowSelection, cullFunctor, RenderDetails::SHADOW, shadowFilter); + const auto shadowSelection = task.addJob("FetchShadowSelection", shadowFilter); + const auto culledShadowSelection = task.addJob("CullShadowSelection", shadowSelection, cullFunctor, RenderDetails::SHADOW, shadowFilter); // Sort - const auto sortedPipelines = addJob("PipelineSortShadowSort", culledShadowSelection); - const auto sortedShapes = addJob("DepthSortShadowMap", sortedPipelines); + const auto sortedPipelines = task.addJob("PipelineSortShadowSort", culledShadowSelection); + const auto sortedShapes = task.addJob("DepthSortShadowMap", sortedPipelines); // GPU jobs: Render to shadow map - addJob("RenderShadowMap", sortedShapes, shapePlumber); + task.addJob("RenderShadowMap", sortedShapes, shapePlumber); - addJob("Teardown", cachedMode); + task.addJob("Teardown", cachedMode); } void RenderShadowTask::configure(const Config& configuration) { diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index d2e58f8362..a4b71308e1 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -44,9 +44,10 @@ signals: class RenderShadowTask : public render::Task { public: using Config = RenderShadowTaskConfig; - using JobModel = Model; + using JobModel = render::Task::Model; - RenderShadowTask(render::CullFunctor shouldRender); + RenderShadowTask() {} + void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender); void configure(const Config& configuration); }; diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index 12252743a7..cdcad638af 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -17,13 +17,11 @@ using namespace render; const Selection::Name ZoneRendererTask::ZONES_SELECTION { "RankedZones" }; -ZoneRendererTask::ZoneRendererTask(const Inputs& inputs) { +void ZoneRendererTask::build(render::Task& task, const Varying& input, Varying& ouput) { - const auto zoneItems = addJob("FilterZones", inputs, ZONES_SELECTION); + const auto zoneItems = task.addJob("FilterZones", input, ZONES_SELECTION.c_str()); // just draw them... - addJob("DrawZones", zoneItems); - + task.addJob("DrawZones", zoneItems); } - diff --git a/libraries/render-utils/src/ZoneRenderer.h b/libraries/render-utils/src/ZoneRenderer.h index 941a99772d..a5585644d5 100644 --- a/libraries/render-utils/src/ZoneRenderer.h +++ b/libraries/render-utils/src/ZoneRenderer.h @@ -14,7 +14,7 @@ #include "render/Engine.h" -class ZoneRendererConfig : public render::Job::Config { +class ZoneRendererConfig : public render::Task::Config { Q_OBJECT Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) public: @@ -37,7 +37,9 @@ public: using Config = ZoneRendererConfig; using JobModel = Model; - ZoneRendererTask(const Inputs& inputs); + ZoneRendererTask() {} + + void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs); void configure(const Config& config) { _maxDrawn = config.maxDrawn; } diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 970cc142e0..15dafce29b 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -25,6 +25,9 @@ using namespace render; Engine::Engine() : _sceneContext(std::make_shared()), _renderContext(std::make_shared()) { +} + +void Engine::build() { addJob("Stats"); } diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index de8340c33e..f513912f4f 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -25,6 +25,7 @@ namespace render { public: Engine(); + void build(); ~Engine() = default; // Load any persisted settings, and set up the presets diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index 1c044d2db4..68422a021c 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -57,6 +57,7 @@ void SliceItems::run(const SceneContextPointer& sceneContext, const RenderContex void SelectItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { auto& scene = sceneContext->_scene; + outItems.clear(); auto selection = scene->getSelection(_name); const auto& selectedItems = selection.getItems(); if (!selectedItems.empty()) { diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index 671cdfff8f..f3d9db7a88 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -17,17 +17,17 @@ using namespace render; -RenderFetchCullSortTask::RenderFetchCullSortTask(CullFunctor cullFunctor) { +void RenderFetchCullSortTask::build(Task& task, const Varying& input, Varying& output, CullFunctor cullFunctor) { cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; // CPU jobs: // Fetch and cull the items from the scene auto spatialFilter = ItemFilter::Builder::visibleWorldItems().withoutLayered(); - const auto spatialSelection = addJob("FetchSceneSelection", spatialFilter); - const auto culledSpatialSelection = addJob("CullSceneSelection", spatialSelection, cullFunctor, RenderDetails::ITEM, spatialFilter); + const auto spatialSelection = task.addJob("FetchSceneSelection", spatialFilter); + const auto culledSpatialSelection = task.addJob("CullSceneSelection", spatialSelection, cullFunctor, RenderDetails::ITEM, spatialFilter); // Overlays are not culled - const auto nonspatialSelection = addJob("FetchOverlaySelection"); + const auto nonspatialSelection = task.addJob("FetchOverlaySelection"); // Multi filter visible items into different buckets const int NUM_SPATIAL_FILTERS = 4; @@ -49,22 +49,22 @@ RenderFetchCullSortTask::RenderFetchCullSortTask(CullFunctor cullFunctor) { ItemFilter::Builder::background() } }; const auto filteredSpatialBuckets = - addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters) + task.addJob>("FilterSceneSelection", culledSpatialSelection, spatialFilters) .get::ItemBoundsArray>(); const auto filteredNonspatialBuckets = - addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters) + task.addJob>("FilterOverlaySelection", nonspatialSelection, nonspatialFilters) .get::ItemBoundsArray>(); // Extract opaques / transparents / lights / overlays - const auto opaques = addJob("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]); - const auto transparents = addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); + const auto opaques = task.addJob("DepthSortOpaque", filteredSpatialBuckets[OPAQUE_SHAPE_BUCKET]); + const auto transparents = task.addJob("DepthSortTransparent", filteredSpatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto lights = filteredSpatialBuckets[LIGHT_BUCKET]; const auto metas = filteredSpatialBuckets[META_BUCKET]; - const auto overlayOpaques = addJob("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]); - const auto overlayTransparents = addJob("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); + const auto overlayOpaques = task.addJob("DepthSortOverlayOpaque", filteredNonspatialBuckets[OPAQUE_SHAPE_BUCKET]); + const auto overlayTransparents = task.addJob("DepthSortOverlayTransparent", filteredNonspatialBuckets[TRANSPARENT_SHAPE_BUCKET], DepthSortItems(false)); const auto background = filteredNonspatialBuckets[BACKGROUND_BUCKET]; - setOutput(Output{{ + output = Varying(Output{{ opaques, transparents, lights, metas, overlayOpaques, overlayTransparents, background, spatialSelection }}); } diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index 1af74939c9..a5db245228 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -34,9 +34,11 @@ public: }; using Output = std::array; - using JobModel = ModelO; + using JobModel = render::Task::ModelO; - RenderFetchCullSortTask(render::CullFunctor cullFunctor); + RenderFetchCullSortTask() {} + + void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); }; #endif // hifi_RenderFetchCullSortTask_h diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 4e3aa79c8d..4370d7956f 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -542,7 +542,10 @@ public: template Model(const Varying& input, A&&... args) : - Concept(std::make_shared()), _data(Data(std::forward(args)...)), _input(input), _output(Output()) { + Concept(std::make_shared()), + _data(Data(std::forward(args)...)), + _input(input), + _output(Output()) { applyConfiguration(); } @@ -585,31 +588,47 @@ public: _concept->setCPURunTime((double)(usecTimestampNow() - start) / 1000.0); } - protected: +protected: ConceptPointer _concept; std::string _name = ""; }; + +template void jobBuild(T& data, const Varying& input, Varying& output, A&&... args) { + data.build(*(dynamic_cast(&data)), input, output, std::forward(args)...); +} + // A task is a specialized job to run a collection of other jobs // It is defined with JobModel = Task::Model class Task { public: using Config = TaskConfig; using QConfigPointer = Job::QConfigPointer; + using None = Job::None; + using Concept = Job::Concept; + using Jobs = std::vector; - template class Model : public Job::Concept { + template class Model : public Concept { public: using Data = T; - using Config = C; - using Input = Job::None; + using Input = I; + using Output = O; Data _data; + Varying _input; + Varying _output; - const Varying getOutput() const override { return _data._output; } + const Varying getInput() const override { return _input; } + const Varying getOutput() const override { return _output; } template Model(const Varying& input, A&&... args) : - Concept(nullptr), _data(Data(std::forward(args)...)) { + Concept(nullptr), + _data(Data()), + _input(input) { + + jobBuild(_data, _input, _output, std::forward(args)...); + // Recreate the Config to use the templated type _data.template createConfiguration(); _config = _data.getConfiguration(); @@ -621,7 +640,7 @@ public: } void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) override { - auto config = std::static_pointer_cast(_config); + auto config = std::static_pointer_cast(_config); if (config->alwaysEnabled || config->enabled) { for (auto job : _data._jobs) { job.run(sceneContext, renderContext); @@ -629,9 +648,9 @@ public: } } }; - template using ModelO = Model; - - using Jobs = std::vector; + template using ModelI = Model; + template using ModelO = Model; + template using ModelIO = Model; // Create a new job in the container's queue; returns the job's output template const Varying addJob(std::string name, const Varying& input, A&&... args) { @@ -656,7 +675,7 @@ public: } template void setOutput(O&& output) { - _output = Varying(output); + _concept->_output = Varying(output); } template void createConfiguration() { @@ -688,7 +707,6 @@ public: void configure(const QObject& configuration) { for (auto& job : _jobs) { job.applyConfiguration(); - } } @@ -698,12 +716,11 @@ public: } } + protected: - template friend class Model; QConfigPointer _config; Jobs _jobs; - Varying _output; }; } diff --git a/scripts/developer/utilities/render/debugDeferredLighting.js b/scripts/developer/utilities/render/debugDeferredLighting.js index 625f71f8a4..bffa3a2e15 100644 --- a/scripts/developer/utilities/render/debugDeferredLighting.js +++ b/scripts/developer/utilities/render/debugDeferredLighting.js @@ -13,7 +13,7 @@ var qml = Script.resolvePath('deferredLighting.qml'); var window = new OverlayWindow({ title: 'Lighting', source: qml, - width: 400, height:280, + width: 400, height:350, }); window.setPosition(Window.innerWidth - 420, 50); window.closed.connect(function() { Script.stop(); }); diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 778e0e1905..5be37b2b89 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -189,6 +189,11 @@ Column { checked: Render.getConfig("DrawOverlayTransparentBounds")["enabled"] onCheckedChanged: { Render.getConfig("DrawOverlayTransparentBounds")["enabled"] = checked } } + CheckBox { + text: "Zones" + checked: Render.getConfig("DrawZones")["enabled"] + onCheckedChanged: { Render.getConfig("DrawZones")["enabled"] = checked } + } } } diff --git a/tests/render-perf/src/main.cpp b/tests/render-perf/src/main.cpp index b76776b1ab..f407e97a10 100644 --- a/tests/render-perf/src/main.cpp +++ b/tests/render-perf/src/main.cpp @@ -543,9 +543,9 @@ public: assert(items.canCast()); static const QString RENDER_FORWARD = "HIFI_RENDER_FORWARD"; if (QProcessEnvironment::systemEnvironment().contains(RENDER_FORWARD)) { - _renderEngine->addJob("RenderForwardTask", items.get()); + _renderEngine->addJob("RenderForwardTask", items); } else { - _renderEngine->addJob("RenderDeferredTask", items.get()); + _renderEngine->addJob("RenderDeferredTask", items); } _renderEngine->load(); _renderEngine->registerScene(_main3DScene); From a4588285909ff89c7f1e09f19533e8be69a7e9e8 Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 10 Apr 2017 02:30:13 -0700 Subject: [PATCH 13/27] MOving forward with the TaskConcept and TaskModel, all working --- .../render-utils/src/RenderDeferredTask.cpp | 2 +- .../render-utils/src/RenderDeferredTask.h | 4 +- .../render-utils/src/RenderForwardTask.cpp | 2 +- .../render-utils/src/RenderForwardTask.h | 4 +- .../render-utils/src/RenderShadowTask.cpp | 4 +- libraries/render-utils/src/RenderShadowTask.h | 4 +- libraries/render-utils/src/ZoneRenderer.cpp | 2 +- libraries/render-utils/src/ZoneRenderer.h | 6 +- libraries/render/src/render/Engine.cpp | 21 +- libraries/render/src/render/Engine.h | 1 - .../src/render/RenderFetchCullSortTask.cpp | 2 +- .../src/render/RenderFetchCullSortTask.h | 4 +- libraries/render/src/render/Task.cpp | 3 +- libraries/render/src/render/Task.h | 291 ++++++++++-------- 14 files changed, 195 insertions(+), 155 deletions(-) diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 4e9203ad4f..35bf9c0bde 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -50,7 +50,7 @@ using namespace render; extern void initOverlay3DPipelines(render::ShapePlumber& plumber); extern void initDeferredPipelines(render::ShapePlumber& plumber); -void RenderDeferredTask::build(render::Task& task, const render::Varying& input, render::Varying& output) { +void RenderDeferredTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { auto items = input.get(); // Prepare the ShapePipelines diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 9ad61b8f1e..660cae88b0 100644 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -192,14 +192,14 @@ public: void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, const gpu::FramebufferPointer& srcFramebuffer); }; -class RenderDeferredTask : public render::Task { +class RenderDeferredTask { public: using Input = RenderFetchCullSortTask::Output; using JobModel = render::Task::ModelI; RenderDeferredTask() {} - void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); }; #endif // hifi_RenderDeferredTask_h diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 630146c698..8a9d7dfbf3 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -29,7 +29,7 @@ using namespace render; extern void initForwardPipelines(ShapePlumber& plumber); -void RenderForwardTask::build(render::Task& task, const render::Varying& input, render::Varying& output) { +void RenderForwardTask::build(JobModel& task, const render::Varying& input, render::Varying& output) { auto items = input.get(); // Prepare the ShapePipelines diff --git a/libraries/render-utils/src/RenderForwardTask.h b/libraries/render-utils/src/RenderForwardTask.h index 3fcf1b398f..f78ce8f317 100755 --- a/libraries/render-utils/src/RenderForwardTask.h +++ b/libraries/render-utils/src/RenderForwardTask.h @@ -16,14 +16,14 @@ #include #include "LightingModel.h" -class RenderForwardTask : public render::Task { +class RenderForwardTask { public: using Input = RenderFetchCullSortTask::Output; using JobModel = render::Task::ModelI; RenderForwardTask() {} - void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); }; class PrepareFramebuffer { diff --git a/libraries/render-utils/src/RenderShadowTask.cpp b/libraries/render-utils/src/RenderShadowTask.cpp index 04e054c921..ddfe038a1a 100644 --- a/libraries/render-utils/src/RenderShadowTask.cpp +++ b/libraries/render-utils/src/RenderShadowTask.cpp @@ -90,7 +90,7 @@ void RenderShadowMap::run(const render::SceneContextPointer& sceneContext, const }); } -void RenderShadowTask::build(render::Task& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) { +void RenderShadowTask::build(JobModel& task, const render::Varying& input, render::Varying& output, CullFunctor cullFunctor) { cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; // Prepare the ShapePipeline @@ -136,7 +136,7 @@ void RenderShadowTask::build(render::Task& task, const render::Varying& input, r void RenderShadowTask::configure(const Config& configuration) { DependencyManager::get()->setShadowMapEnabled(configuration.enabled); // This is a task, so must still propogate configure() to its Jobs - Task::configure(configuration); +// Task::configure(configuration); } void RenderShadowSetup::run(const SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext, Output& output) { diff --git a/libraries/render-utils/src/RenderShadowTask.h b/libraries/render-utils/src/RenderShadowTask.h index a4b71308e1..9190034b2e 100644 --- a/libraries/render-utils/src/RenderShadowTask.h +++ b/libraries/render-utils/src/RenderShadowTask.h @@ -41,13 +41,13 @@ signals: void dirty(); }; -class RenderShadowTask : public render::Task { +class RenderShadowTask { public: using Config = RenderShadowTaskConfig; using JobModel = render::Task::Model; RenderShadowTask() {} - void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor shouldRender); void configure(const Config& configuration); }; diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index cdcad638af..e2bf9a5d22 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -17,7 +17,7 @@ using namespace render; const Selection::Name ZoneRendererTask::ZONES_SELECTION { "RankedZones" }; -void ZoneRendererTask::build(render::Task& task, const Varying& input, Varying& ouput) { +void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& ouput) { const auto zoneItems = task.addJob("FilterZones", input, ZONES_SELECTION.c_str()); diff --git a/libraries/render-utils/src/ZoneRenderer.h b/libraries/render-utils/src/ZoneRenderer.h index a5585644d5..c55dc2beb4 100644 --- a/libraries/render-utils/src/ZoneRenderer.h +++ b/libraries/render-utils/src/ZoneRenderer.h @@ -27,7 +27,7 @@ signals: protected: }; -class ZoneRendererTask : public render::Task { +class ZoneRendererTask { public: static const render::Selection::Name ZONES_SELECTION; @@ -35,11 +35,11 @@ public: using Inputs = render::ItemBounds; using Config = ZoneRendererConfig; - using JobModel = Model; + using JobModel = render::Task::ModelI; ZoneRendererTask() {} - void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs); void configure(const Config& config) { _maxDrawn = config.maxDrawn; } diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 15dafce29b..3e6ad458fb 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -22,13 +22,22 @@ using namespace render; -Engine::Engine() : - _sceneContext(std::make_shared()), - _renderContext(std::make_shared()) { -} +class EngineTask { +public: -void Engine::build() { - addJob("Stats"); + using JobModel = Task::Model; + + EngineTask() {} + + void build(JobModel& task, const Varying& in, Varying& out) { + task.addJob("Stats"); + } +}; + +Engine::Engine() : Task("Engine", EngineTask::JobModel::factoryModel()), + _sceneContext(std::make_shared()), + _renderContext(std::make_shared()) +{ } void Engine::load() { diff --git a/libraries/render/src/render/Engine.h b/libraries/render/src/render/Engine.h index f513912f4f..de8340c33e 100644 --- a/libraries/render/src/render/Engine.h +++ b/libraries/render/src/render/Engine.h @@ -25,7 +25,6 @@ namespace render { public: Engine(); - void build(); ~Engine() = default; // Load any persisted settings, and set up the presets diff --git a/libraries/render/src/render/RenderFetchCullSortTask.cpp b/libraries/render/src/render/RenderFetchCullSortTask.cpp index f3d9db7a88..d735afa52d 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.cpp +++ b/libraries/render/src/render/RenderFetchCullSortTask.cpp @@ -17,7 +17,7 @@ using namespace render; -void RenderFetchCullSortTask::build(Task& task, const Varying& input, Varying& output, CullFunctor cullFunctor) { +void RenderFetchCullSortTask::build(JobModel& task, const Varying& input, Varying& output, CullFunctor cullFunctor) { cullFunctor = cullFunctor ? cullFunctor : [](const RenderArgs*, const AABox&){ return true; }; // CPU jobs: diff --git a/libraries/render/src/render/RenderFetchCullSortTask.h b/libraries/render/src/render/RenderFetchCullSortTask.h index a5db245228..12bcb9786d 100644 --- a/libraries/render/src/render/RenderFetchCullSortTask.h +++ b/libraries/render/src/render/RenderFetchCullSortTask.h @@ -17,7 +17,7 @@ #include "Task.h" #include "CullTask.h" -class RenderFetchCullSortTask : public render::Task { +class RenderFetchCullSortTask { public: enum Buckets { @@ -38,7 +38,7 @@ public: RenderFetchCullSortTask() {} - void build(render::Task& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); + void build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor); }; #endif // hifi_RenderFetchCullSortTask_h diff --git a/libraries/render/src/render/Task.cpp b/libraries/render/src/render/Task.cpp index c1a917d26a..cd0c938c73 100644 --- a/libraries/render/src/render/Task.cpp +++ b/libraries/render/src/render/Task.cpp @@ -21,6 +21,7 @@ void TaskConfig::refresh() { return; } - _task->configure(*this); + // _task->configure(*this); + _task->applyConfiguration(); } diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 4370d7956f..805f431fcb 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -301,6 +301,7 @@ public: }; class Job; +class JobConcept; class Task; class JobNoIO {}; @@ -432,8 +433,7 @@ public slots: void refresh(); private: - friend class Task; - Task* _task; + JobConcept* _task; }; template void jobConfigure(T& data, const C& configuration) { @@ -458,73 +458,37 @@ template void jobRun(T& data, const SceneContextPoin data.run(sceneContext, renderContext, input, output); } -class GPUJobConfig : public JobConfig { - Q_OBJECT - Q_PROPERTY(double gpuRunTime READ getGPURunTime) - Q_PROPERTY(double batchRunTime READ getBatchRunTime) - - double _msGPURunTime { 0.0 }; - double _msBatchRunTime { 0.0 }; +// The guts of a job +class JobConcept { public: - using Persistent = PersistentConfig; + using Config = JobConfig; + using QConfigPointer = std::shared_ptr; - GPUJobConfig() = default; - GPUJobConfig(bool enabled) : JobConfig(enabled) {} + JobConcept(QConfigPointer config) : _config(config) {} + virtual ~JobConcept() = default; - // Running Time measurement on GPU and for Batch execution - void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; } - double getGPURunTime() const { return _msGPURunTime; } - double getBatchRunTime() const { return _msBatchRunTime; } -}; + virtual const Varying getInput() const { return Varying(); } + virtual const Varying getOutput() const { return Varying(); } -class GPUTaskConfig : public TaskConfig { - Q_OBJECT - Q_PROPERTY(double gpuRunTime READ getGPURunTime) - Q_PROPERTY(double batchRunTime READ getBatchRunTime) + virtual QConfigPointer& getConfiguration() { return _config; } + virtual void applyConfiguration() = 0; - double _msGPURunTime { 0.0 }; - double _msBatchRunTime { 0.0 }; -public: + virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0; - using Persistent = PersistentConfig; +protected: + void setCPURunTime(double mstime) { std::static_pointer_cast(_config)->setCPURunTime(mstime); } + QConfigPointer _config; - GPUTaskConfig() = default; - GPUTaskConfig(bool enabled) : TaskConfig(enabled) {} - - // Running Time measurement on GPU and for Batch execution - void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; } - double getGPURunTime() const { return _msGPURunTime; } - double getBatchRunTime() const { return _msBatchRunTime; } + friend class Job; }; class Job { public: + using Concept = JobConcept; using Config = JobConfig; using QConfigPointer = std::shared_ptr; using None = JobNoIO; - - // The guts of a job - class Concept { - public: - Concept(QConfigPointer config) : _config(config) {} - virtual ~Concept() = default; - - virtual const Varying getInput() const { return Varying(); } - virtual const Varying getOutput() const { return Varying(); } - - virtual QConfigPointer& getConfiguration() { return _config; } - virtual void applyConfiguration() = 0; - - virtual void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) = 0; - - protected: - void setCPURunTime(double mstime) { std::static_pointer_cast(_config)->setCPURunTime(mstime); } - - QConfigPointer _config; - - friend class Job; - }; using ConceptPointer = std::shared_ptr; template class Model : public Concept { @@ -549,6 +513,12 @@ public: applyConfiguration(); } + template + static std::shared_ptr factoryModel(const Varying& input, A&&... args) { + return std::make_shared(input, std::forward(args)...); + } + + void applyConfiguration() override { jobConfigure(_data, *std::static_pointer_cast(_config)); } @@ -593,14 +563,15 @@ protected: std::string _name = ""; }; - -template void jobBuild(T& data, const Varying& input, Varying& output, A&&... args) { - data.build(*(dynamic_cast(&data)), input, output, std::forward(args)...); -} +/* +template void taskBuild(T& data, typename T::JobModel* task, const Varying& input, Varying& output, A&&... args) { + data.build(*(task), input, output, std::forward(args)...); +}*/ // A task is a specialized job to run a collection of other jobs // It is defined with JobModel = Task::Model -class Task { + +class Task : public Job { public: using Config = TaskConfig; using QConfigPointer = Job::QConfigPointer; @@ -608,119 +579,179 @@ public: using Concept = Job::Concept; using Jobs = std::vector; - template class Model : public Concept { + Task(std::string name, ConceptPointer concept) : Job(name, concept) {} + + class TaskConcept : public Concept { + public: + Varying _input; + Varying _output; + Jobs _jobs; + + const Varying getInput() const override { return _input; } + const Varying getOutput() const override { return _output; } + + TaskConcept(const Varying& input, QConfigPointer config) : Concept(config), _input(input) {} + + // Create a new job in the container's queue; returns the job's output + template const Varying addJob(std::string name, const Varying& input, NA&&... args) { + _jobs.emplace_back(name, (NT::JobModel::factoryModel(input, std::forward(args)...))); + QConfigPointer config = _jobs.back().getConfiguration(); + config->setParent(getConfiguration().get()); + config->setObjectName(name.c_str()); + + // Connect loaded->refresh + QObject::connect(config.get(), SIGNAL(loaded()), getConfiguration().get(), SLOT(refresh())); + static const char* DIRTY_SIGNAL = "dirty()"; + if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { + // Connect dirty->refresh if defined + QObject::connect(config.get(), SIGNAL(dirty()), getConfiguration().get(), SLOT(refresh())); + } + + return _jobs.back().getOutput(); + } + template const Varying addJob(std::string name, NA&&... args) { + const auto input = Varying(typename NT::JobModel::Input()); + return addJob(name, input, std::forward(args)...); + } + }; + + template class TaskModel : public TaskConcept { public: using Data = T; using Input = I; using Output = O; Data _data; - Varying _input; - Varying _output; - const Varying getInput() const override { return _input; } - const Varying getOutput() const override { return _output; } + TaskModel(const Varying& input) : + TaskConcept(input, nullptr), + _data(Data()) {} template - Model(const Varying& input, A&&... args) : - Concept(nullptr), - _data(Data()), - _input(input) { + static std::shared_ptr factoryModel(const Varying& input, A&&... args) { + auto model = std::make_shared(input); - jobBuild(_data, _input, _output, std::forward(args)...); + model->_data.build(*(model), model->_input, model->_output, std::forward(args)...); // Recreate the Config to use the templated type - _data.template createConfiguration(); - _config = _data.getConfiguration(); - applyConfiguration(); + model->createConfiguration(); + model->applyConfiguration(); + + return model; + } + + template + static std::shared_ptr factoryModel(A&&... args) { + const auto input = Varying(Input()); + return factoryModel(input, std::forward(args)...); + } + + void createConfiguration() { + auto config = std::make_shared(); + if (_config) { + // Transfer children to the new configuration + auto children = _config->children(); + for (auto& child : children) { + child->setParent(config.get()); + QObject::connect(child, SIGNAL(loaded()), config.get(), SLOT(refresh())); + static const char* DIRTY_SIGNAL = "dirty()"; + if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { + // Connect dirty->refresh if defined + QObject::connect(child, SIGNAL(dirty()), config.get(), SLOT(refresh())); + } + } + } + _config = config; + std::static_pointer_cast(_config)->_task = this; + } + + QConfigPointer& getConfiguration() override { + if (!_config) { + createConfiguration(); + } + return _config; } void applyConfiguration() override { jobConfigure(_data, *std::static_pointer_cast(_config)); + for (auto& job : _jobs) { + job.applyConfiguration(); + } } void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) override { auto config = std::static_pointer_cast(_config); if (config->alwaysEnabled || config->enabled) { - for (auto job : _data._jobs) { + for (auto job : _jobs) { job.run(sceneContext, renderContext); } } } }; - template using ModelI = Model; - template using ModelO = Model; - template using ModelIO = Model; + template using Model = TaskModel; + template using ModelI = TaskModel; + template using ModelO = TaskModel; + template using ModelIO = TaskModel; - // Create a new job in the container's queue; returns the job's output + // Create a new job in the Task's queue; returns the job's output template const Varying addJob(std::string name, const Varying& input, A&&... args) { - _jobs.emplace_back(name, std::make_shared(input, std::forward(args)...)); - QConfigPointer config = _jobs.back().getConfiguration(); - config->setParent(getConfiguration().get()); - config->setObjectName(name.c_str()); - - // Connect loaded->refresh - QObject::connect(config.get(), SIGNAL(loaded()), getConfiguration().get(), SLOT(refresh())); - static const char* DIRTY_SIGNAL = "dirty()"; - if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { - // Connect dirty->refresh if defined - QObject::connect(config.get(), SIGNAL(dirty()), getConfiguration().get(), SLOT(refresh())); - } - - return _jobs.back().getOutput(); + return std::static_pointer_cast( _concept)->addJob(name, input, std::forward(args)...); } template const Varying addJob(std::string name, A&&... args) { const auto input = Varying(typename T::JobModel::Input()); - return addJob(name, input, std::forward(args)...); + return std::static_pointer_cast( _concept)->addJob(name, input, std::forward(args)...); } template void setOutput(O&& output) { _concept->_output = Varying(output); } - template void createConfiguration() { - auto config = std::make_shared(); - if (_config) { - // Transfer children to the new configuration - auto children = _config->children(); - for (auto& child : children) { - child->setParent(config.get()); - QObject::connect(child, SIGNAL(loaded()), config.get(), SLOT(refresh())); - static const char* DIRTY_SIGNAL = "dirty()"; - if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { - // Connect dirty->refresh if defined - QObject::connect(child, SIGNAL(dirty()), config.get(), SLOT(refresh())); - } - } - } - _config = config; - std::static_pointer_cast(_config)->_task = this; - } - std::shared_ptr getConfiguration() { - if (!_config) { - createConfiguration(); - } - return std::static_pointer_cast(_config); + return std::static_pointer_cast(_concept->getConfiguration()); } - void configure(const QObject& configuration) { - for (auto& job : _jobs) { - job.applyConfiguration(); - } - } - - void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) { - for (auto job : _jobs) { - job.run(sceneContext, renderContext); - } - } - - protected: +}; - QConfigPointer _config; - Jobs _jobs; +// Versions of the COnfig integrating a gpu & batch timer +class GPUJobConfig : public JobConfig { + Q_OBJECT + Q_PROPERTY(double gpuRunTime READ getGPURunTime) + Q_PROPERTY(double batchRunTime READ getBatchRunTime) + + double _msGPURunTime { 0.0 }; + double _msBatchRunTime { 0.0 }; +public: + using Persistent = PersistentConfig; + + GPUJobConfig() = default; + GPUJobConfig(bool enabled) : JobConfig(enabled) {} + + // Running Time measurement on GPU and for Batch execution + void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; } + double getGPURunTime() const { return _msGPURunTime; } + double getBatchRunTime() const { return _msBatchRunTime; } +}; + +class GPUTaskConfig : public TaskConfig { + Q_OBJECT + Q_PROPERTY(double gpuRunTime READ getGPURunTime) + Q_PROPERTY(double batchRunTime READ getBatchRunTime) + + double _msGPURunTime { 0.0 }; + double _msBatchRunTime { 0.0 }; +public: + + using Persistent = PersistentConfig; + + + GPUTaskConfig() = default; + GPUTaskConfig(bool enabled) : TaskConfig(enabled) {} + + // Running Time measurement on GPU and for Batch execution + void setGPUBatchRunTime(double msGpuTime, double msBatchTime) { _msGPURunTime = msGpuTime; _msBatchRunTime = msBatchTime; } + double getGPURunTime() const { return _msGPURunTime; } + double getBatchRunTime() const { return _msBatchRunTime; } }; } From e7fb18bd2f578d05cee3ea0bb7fd9f365879e8dc Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 10 Apr 2017 02:51:19 -0700 Subject: [PATCH 14/27] MOving forward with the TaskConcept and TaskModel, all working --- libraries/render/src/render/Task.h | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 805f431fcb..49499896da 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -416,6 +416,8 @@ signals: class TaskConfig : public JobConfig { Q_OBJECT public: + using QConfigPointer = std::shared_ptr; + using Persistent = PersistentConfig; TaskConfig() = default ; @@ -429,11 +431,29 @@ public: return findChild(name); } + void connectSubJobConfig(QConfigPointer jobConfig, const std::string& name) { + // QConfigPointer config = _jobs.back().getConfiguration(); + jobConfig->setParent(this); + jobConfig->setObjectName(name.c_str()); + + // Connect loaded->refresh + // QObject::connect(config.get(), SIGNAL(loaded()), getConfiguration().get(), SLOT(refresh())); + QObject::connect(jobConfig.get(), SIGNAL(loaded()), this, SLOT(refresh())); + static const char* DIRTY_SIGNAL = "dirty()"; + // if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { + if (jobConfig->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { + // Connect dirty->refresh if defined + // QObject::connect(config.get(), SIGNAL(dirty()), getConfiguration().get(), SLOT(refresh())); + QObject::connect(jobConfig.get(), SIGNAL(dirty()), this, SLOT(refresh())); + } + } + public slots: void refresh(); private: - JobConcept* _task; + friend Task; + JobConcept* _task; }; template void jobConfigure(T& data, const C& configuration) { @@ -595,7 +615,7 @@ public: // Create a new job in the container's queue; returns the job's output template const Varying addJob(std::string name, const Varying& input, NA&&... args) { _jobs.emplace_back(name, (NT::JobModel::factoryModel(input, std::forward(args)...))); - QConfigPointer config = _jobs.back().getConfiguration(); + /* QConfigPointer config = _jobs.back().getConfiguration(); config->setParent(getConfiguration().get()); config->setObjectName(name.c_str()); @@ -605,7 +625,9 @@ public: if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { // Connect dirty->refresh if defined QObject::connect(config.get(), SIGNAL(dirty()), getConfiguration().get(), SLOT(refresh())); - } + }*/ + + std::static_pointer_cast(getConfiguration())->connectSubJobConfig(_jobs.back().getConfiguration(), name); return _jobs.back().getOutput(); } From 4a47737d0b11df690e5ca3412325341b0347f3e8 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 10 Apr 2017 19:01:49 -0700 Subject: [PATCH 15/27] REfining the Config behavior, trying to pr next --- libraries/render-utils/src/ZoneRenderer.h | 2 + libraries/render/src/render/DrawTask.h | 2 +- libraries/render/src/render/Engine.cpp | 2 +- libraries/render/src/render/Task.cpp | 31 +++++++- libraries/render/src/render/Task.h | 78 +++++-------------- .../utilities/render/deferredLighting.qml | 2 +- 6 files changed, 56 insertions(+), 61 deletions(-) diff --git a/libraries/render-utils/src/ZoneRenderer.h b/libraries/render-utils/src/ZoneRenderer.h index c55dc2beb4..1218608400 100644 --- a/libraries/render-utils/src/ZoneRenderer.h +++ b/libraries/render-utils/src/ZoneRenderer.h @@ -19,6 +19,8 @@ class ZoneRendererConfig : public render::Task::Config { Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) public: + ZoneRendererConfig() : render::Task::Config(false) {} + int maxDrawn { -1 }; signals: diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index a9c5f3a4d8..d1856cb66e 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -52,7 +52,7 @@ class DrawBounds { public: class Config : public render::JobConfig { public: - Config() : JobConfig(false) {} + Config(bool enabled = false) : JobConfig(enabled) {} }; using Inputs = render::ItemBounds; diff --git a/libraries/render/src/render/Engine.cpp b/libraries/render/src/render/Engine.cpp index 3e6ad458fb..08efb7b281 100644 --- a/libraries/render/src/render/Engine.cpp +++ b/libraries/render/src/render/Engine.cpp @@ -34,7 +34,7 @@ public: } }; -Engine::Engine() : Task("Engine", EngineTask::JobModel::factoryModel()), +Engine::Engine() : Task("Engine", EngineTask::JobModel::create()), _sceneContext(std::make_shared()), _renderContext(std::make_shared()) { diff --git a/libraries/render/src/render/Task.cpp b/libraries/render/src/render/Task.cpp index cd0c938c73..13476f102e 100644 --- a/libraries/render/src/render/Task.cpp +++ b/libraries/render/src/render/Task.cpp @@ -15,13 +15,42 @@ using namespace render; +void TaskConfig::connectChildConfig(QConfigPointer childConfig, const std::string& name) { + childConfig->setParent(this); + childConfig->setObjectName(name.c_str()); + + // Connect loaded->refresh + QObject::connect(childConfig.get(), SIGNAL(loaded()), this, SLOT(refresh())); + static const char* DIRTY_SIGNAL = "dirty()"; + if (childConfig->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { + // Connect dirty->refresh if defined + QObject::connect(childConfig.get(), SIGNAL(dirty()), this, SLOT(refresh())); + } +} + +void TaskConfig::transferChildrenConfigs(QConfigPointer source) { + if (!source) { + return; + } + // Transfer children to the new configuration + auto children = source->children(); + for (auto& child : children) { + child->setParent(this); + QObject::connect(child, SIGNAL(loaded()), this, SLOT(refresh())); + static const char* DIRTY_SIGNAL = "dirty()"; + if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { + // Connect dirty->refresh if defined + QObject::connect(child, SIGNAL(dirty()), this, SLOT(refresh())); + } + } +} + void TaskConfig::refresh() { if (QThread::currentThread() != thread()) { QMetaObject::invokeMethod(this, "refresh", Qt::BlockingQueuedConnection); return; } - // _task->configure(*this); _task->applyConfiguration(); } diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 49499896da..855274e701 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -431,22 +431,8 @@ public: return findChild(name); } - void connectSubJobConfig(QConfigPointer jobConfig, const std::string& name) { - // QConfigPointer config = _jobs.back().getConfiguration(); - jobConfig->setParent(this); - jobConfig->setObjectName(name.c_str()); - - // Connect loaded->refresh - // QObject::connect(config.get(), SIGNAL(loaded()), getConfiguration().get(), SLOT(refresh())); - QObject::connect(jobConfig.get(), SIGNAL(loaded()), this, SLOT(refresh())); - static const char* DIRTY_SIGNAL = "dirty()"; - // if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { - if (jobConfig->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { - // Connect dirty->refresh if defined - // QObject::connect(config.get(), SIGNAL(dirty()), getConfiguration().get(), SLOT(refresh())); - QObject::connect(jobConfig.get(), SIGNAL(dirty()), this, SLOT(refresh())); - } - } + void connectChildConfig(QConfigPointer childConfig, const std::string& name); + void transferChildrenConfigs(QConfigPointer source); public slots: void refresh(); @@ -525,8 +511,8 @@ public: const Varying getOutput() const override { return _output; } template - Model(const Varying& input, A&&... args) : - Concept(std::make_shared()), + Model(const Varying& input, QConfigPointer config, A&&... args) : + Concept(config), _data(Data(std::forward(args)...)), _input(input), _output(Output()) { @@ -534,8 +520,8 @@ public: } template - static std::shared_ptr factoryModel(const Varying& input, A&&... args) { - return std::make_shared(input, std::forward(args)...); + static std::shared_ptr create(const Varying& input, A&&... args) { + return std::make_shared(input, std::make_shared(), std::forward(args)...); } @@ -583,11 +569,6 @@ protected: std::string _name = ""; }; -/* -template void taskBuild(T& data, typename T::JobModel* task, const Varying& input, Varying& output, A&&... args) { - data.build(*(task), input, output, std::forward(args)...); -}*/ - // A task is a specialized job to run a collection of other jobs // It is defined with JobModel = Task::Model @@ -614,20 +595,10 @@ public: // Create a new job in the container's queue; returns the job's output template const Varying addJob(std::string name, const Varying& input, NA&&... args) { - _jobs.emplace_back(name, (NT::JobModel::factoryModel(input, std::forward(args)...))); - /* QConfigPointer config = _jobs.back().getConfiguration(); - config->setParent(getConfiguration().get()); - config->setObjectName(name.c_str()); + _jobs.emplace_back(name, (NT::JobModel::create(input, std::forward(args)...))); - // Connect loaded->refresh - QObject::connect(config.get(), SIGNAL(loaded()), getConfiguration().get(), SLOT(refresh())); - static const char* DIRTY_SIGNAL = "dirty()"; - if (config->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { - // Connect dirty->refresh if defined - QObject::connect(config.get(), SIGNAL(dirty()), getConfiguration().get(), SLOT(refresh())); - }*/ - - std::static_pointer_cast(getConfiguration())->connectSubJobConfig(_jobs.back().getConfiguration(), name); + // Conect the child config to this task's config + std::static_pointer_cast(getConfiguration())->connectChildConfig(_jobs.back().getConfiguration(), name); return _jobs.back().getOutput(); } @@ -645,13 +616,14 @@ public: Data _data; - TaskModel(const Varying& input) : - TaskConcept(input, nullptr), + TaskModel(const Varying& input, QConfigPointer config) : + TaskConcept(input, config), _data(Data()) {} template - static std::shared_ptr factoryModel(const Varying& input, A&&... args) { - auto model = std::make_shared(input); + static std::shared_ptr create(const Varying& input, A&&... args) { + auto model = std::make_shared(input, std::make_shared()); + // std::static_pointer_cast(model->_config)->_task = model.get(); model->_data.build(*(model), model->_input, model->_output, std::forward(args)...); @@ -663,27 +635,19 @@ public: } template - static std::shared_ptr factoryModel(A&&... args) { + static std::shared_ptr create(A&&... args) { const auto input = Varying(Input()); - return factoryModel(input, std::forward(args)...); + return create(input, std::forward(args)...); } void createConfiguration() { + // A brand new config auto config = std::make_shared(); - if (_config) { - // Transfer children to the new configuration - auto children = _config->children(); - for (auto& child : children) { - child->setParent(config.get()); - QObject::connect(child, SIGNAL(loaded()), config.get(), SLOT(refresh())); - static const char* DIRTY_SIGNAL = "dirty()"; - if (child->metaObject()->indexOfSignal(DIRTY_SIGNAL) != -1) { - // Connect dirty->refresh if defined - QObject::connect(child, SIGNAL(dirty()), config.get(), SLOT(refresh())); - } - } - } + // Make sure we transfer the former children configs to the new config + config->transferChildrenConfigs(_config); + // swap _config = config; + // Capture this std::static_pointer_cast(_config)->_task = this; } diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index 5be37b2b89..229a2d1c3b 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -192,7 +192,7 @@ Column { CheckBox { text: "Zones" checked: Render.getConfig("DrawZones")["enabled"] - onCheckedChanged: { Render.getConfig("DrawZones")["enabled"] = checked } + onCheckedChanged: { Render.getConfig("ZoneRenderer")["enabled"] = checked; Render.getConfig("DrawZones")["enabled"] = checked; } } } } From 5d7accca2ba80b9edb0085005f8a39a6047ef70d Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 10 Apr 2017 21:12:00 -0700 Subject: [PATCH 16/27] Avoiding the mac compilation problem maybe --- libraries/render/src/render/Task.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index 855274e701..adebc77af3 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -688,10 +688,6 @@ public: return std::static_pointer_cast( _concept)->addJob(name, input, std::forward(args)...); } - template void setOutput(O&& output) { - _concept->_output = Varying(output); - } - std::shared_ptr getConfiguration() { return std::static_pointer_cast(_concept->getConfiguration()); } From 80c781bcdcf38062e842dbde66af861acb4c338c Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Mon, 10 Apr 2017 22:17:12 -0700 Subject: [PATCH 17/27] Fixing warning on mac and more description of the Task class --- libraries/render/src/render/FilterTask.cpp | 3 --- libraries/render/src/render/Task.h | 8 ++++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index 68422a021c..22d5feffe4 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -37,9 +37,6 @@ void FilterLayeredItems::run(const SceneContextPointer& sceneContext, const Rend } void SliceItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { - auto& scene = sceneContext->_scene; - - // Now we have a selection of items to render outItems.clear(); std::static_pointer_cast(renderContext->jobConfig)->setNumItems((int)inItems.size()); diff --git a/libraries/render/src/render/Task.h b/libraries/render/src/render/Task.h index adebc77af3..03824bd14d 100644 --- a/libraries/render/src/render/Task.h +++ b/libraries/render/src/render/Task.h @@ -570,8 +570,12 @@ protected: }; // A task is a specialized job to run a collection of other jobs -// It is defined with JobModel = Task::Model - +// It can be created on any type T by aliasing the type JobModel in the class T +// using JobModel = Task::Model +// The class T is expected to have a "build" method acting as a constructor. +// The build method is where child Jobs can be added internally to the task +// where the input of the task can be setup to feed the child jobs +// and where the output of the task is defined class Task : public Job { public: using Config = TaskConfig; From 1dd98af1ddeb9432f6aecc9590190ba2799feaab Mon Sep 17 00:00:00 2001 From: Sam Cake Date: Tue, 11 Apr 2017 01:21:45 -0700 Subject: [PATCH 18/27] And introduce a clean sorted select of the items so we keep the order of rendering of the boxes of the zone in the ZOne stack order, the color of box reflect the order (from red to blue) --- libraries/render-utils/src/ZoneRenderer.cpp | 2 +- libraries/render/src/render/DrawTask.cpp | 5 +++ libraries/render/src/render/DrawTask.h | 1 + libraries/render/src/render/FilterTask.cpp | 40 +++++++++++++++++-- libraries/render/src/render/FilterTask.h | 11 +++++ libraries/render/src/render/Selection.cpp | 10 +++-- libraries/render/src/render/Selection.h | 7 +++- .../render/src/render/drawItemBounds.slv | 6 +-- 8 files changed, 68 insertions(+), 14 deletions(-) diff --git a/libraries/render-utils/src/ZoneRenderer.cpp b/libraries/render-utils/src/ZoneRenderer.cpp index e2bf9a5d22..2cabe58c33 100644 --- a/libraries/render-utils/src/ZoneRenderer.cpp +++ b/libraries/render-utils/src/ZoneRenderer.cpp @@ -19,7 +19,7 @@ const Selection::Name ZoneRendererTask::ZONES_SELECTION { "RankedZones" }; void ZoneRendererTask::build(JobModel& task, const Varying& input, Varying& ouput) { - const auto zoneItems = task.addJob("FilterZones", input, ZONES_SELECTION.c_str()); + const auto zoneItems = task.addJob("FilterZones", input, ZONES_SELECTION.c_str()); // just draw them... task.addJob("DrawZones", zoneItems); diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index e8537e3452..1b4cd48ffc 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -150,6 +150,7 @@ const gpu::PipelinePointer DrawBounds::getPipeline() { _cornerLocation = program->getUniforms().findLocation("inBoundPos"); _scaleLocation = program->getUniforms().findLocation("inBoundDim"); + _colorLocation = program->getUniforms().findLocation("inColor"); auto state = std::make_shared(); state->setDepthTest(true, false, gpu::LESS_EQUAL); @@ -184,12 +185,16 @@ void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContex assert(_scaleLocation >= 0); // Render bounds + float numItems = (float) items.size(); + float itemNum = 0.0f; for (const auto& item : items) { batch._glUniform3fv(_cornerLocation, 1, (const float*)(&item.bound.getCorner())); batch._glUniform3fv(_scaleLocation, 1, (const float*)(&item.bound.getScale())); + batch._glUniform4fv(_colorLocation, 1, (const float*)(&glm::vec4(glm::vec3(itemNum / numItems), 1.0f))); static const int NUM_VERTICES_PER_CUBE = 24; batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE, 0); + itemNum += 1.0f; } }); } diff --git a/libraries/render/src/render/DrawTask.h b/libraries/render/src/render/DrawTask.h index d1856cb66e..9a74802888 100755 --- a/libraries/render/src/render/DrawTask.h +++ b/libraries/render/src/render/DrawTask.h @@ -67,6 +67,7 @@ private: gpu::PipelinePointer _boundsPipeline; int _cornerLocation { -1 }; int _scaleLocation { -1 }; + int _colorLocation { -1 }; }; } diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index 22d5feffe4..76b42b0813 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -52,12 +52,13 @@ void SliceItems::run(const SceneContextPointer& sceneContext, const RenderContex } void SelectItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { - auto& scene = sceneContext->_scene; - - outItems.clear(); - auto selection = scene->getSelection(_name); + auto selection = sceneContext->_scene->getSelection(_name); const auto& selectedItems = selection.getItems(); + outItems.clear(); + if (!selectedItems.empty()) { + outItems.reserve(selectedItems.size()); + for (auto src : inItems) { if (selection.contains(src.id)) { outItems.emplace_back(src); @@ -66,6 +67,37 @@ void SelectItems::run(const SceneContextPointer& sceneContext, const RenderConte } } +void SelectSortItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems) { + auto selection = sceneContext->_scene->getSelection(_name); + const auto& selectedItems = selection.getItems(); + outItems.clear(); + + if (!selectedItems.empty()) { + struct Pair { int src; int dst; }; + std::vector indices; + indices.reserve(selectedItems.size()); + + // Collect + for (int srcIndex = 0; (srcIndex < inItems.size()) && (indices.size() < selectedItems.size()) ; srcIndex++ ) { + int index = selection.find(inItems[srcIndex].id); + if (index != Selection::NOT_FOUND) { + indices.emplace_back( Pair{ srcIndex, index } ); + } + } + + // Then sort + if (!indices.empty()) { + std::sort(indices.begin(), indices.end(), [] (Pair a, Pair b) { + return (a.dst < b.dst); + }); + + for (auto& pair: indices) { + outItems.emplace_back(inItems[pair.src]); + } + } + } +} + void MetaToSubItems::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemIDs& outItems) { auto& scene = sceneContext->_scene; diff --git a/libraries/render/src/render/FilterTask.h b/libraries/render/src/render/FilterTask.h index 46a9ef25bd..00019fa1ae 100644 --- a/libraries/render/src/render/FilterTask.h +++ b/libraries/render/src/render/FilterTask.h @@ -121,6 +121,17 @@ namespace render { void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); }; + // Same as SelectItems but reorder the output to match the selection order + class SelectSortItems { + public: + using JobModel = Job::ModelIO; + + std::string _name; + SelectSortItems(const Selection::Name& name) : _name(name) {} + + void run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext, const ItemBounds& inItems, ItemBounds& outItems); + }; + // From meta-Items, generate the sub-items class MetaToSubItems { public: diff --git a/libraries/render/src/render/Selection.cpp b/libraries/render/src/render/Selection.cpp index 5ac0f415f4..46941ae440 100644 --- a/libraries/render/src/render/Selection.cpp +++ b/libraries/render/src/render/Selection.cpp @@ -56,11 +56,13 @@ Selection::Selection(const Name& name, const ItemIDs& items) : { } -bool Selection::contains(ItemID id) const { +int Selection::find(ItemID id) const { + int index = 0; for (auto selected : _items) { if (selected == id) { - return true; + return index; } + index++; } - return false; -} \ No newline at end of file + return NOT_FOUND; +} diff --git a/libraries/render/src/render/Selection.h b/libraries/render/src/render/Selection.h index 6c5f6aab10..2c7ce710cd 100644 --- a/libraries/render/src/render/Selection.h +++ b/libraries/render/src/render/Selection.h @@ -34,7 +34,12 @@ namespace render { const ItemIDs& getItems() const { return _items; } bool isEmpty() const { return _items.empty(); } - bool contains(ItemID id) const; + + // Test if the ID is in the selection, return the index or -1 if not present + static const int NOT_FOUND{ -1 }; + + int find(ItemID id) const; + bool contains(ItemID id) const { return find(id) > NOT_FOUND; } protected: Name _name; diff --git a/libraries/render/src/render/drawItemBounds.slv b/libraries/render/src/render/drawItemBounds.slv index cf1eab7163..af1e31fbf4 100644 --- a/libraries/render/src/render/drawItemBounds.slv +++ b/libraries/render/src/render/drawItemBounds.slv @@ -20,7 +20,7 @@ uniform vec3 inBoundPos; uniform vec3 inBoundDim; -uniform ivec4 inCellLocation; +uniform vec4 inColor; out vec4 varColor; out vec2 varTexcoord; @@ -59,9 +59,7 @@ void main(void) { TransformObject obj = getTransformObject(); <$transformModelToClipPos(cam, obj, pos, gl_Position)$> - bool subcell = bool((inCellLocation.z)); - float cellDepth = float(inCellLocation.w); - varColor = vec4(colorWheel(fract(cellDepth / 5.0)), 1.0 - float(subcell)); + varColor = vec4(colorWheel(inColor.x), 1.0); varTexcoord = vec2(cubeVec.w, length(inBoundDim)); } \ No newline at end of file From 612acbc6d5fab07c7fb756c320fe8d147e0c3ed6 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 11 Apr 2017 10:56:58 -0700 Subject: [PATCH 19/27] Avoid pointers on temp var --- libraries/render/src/render/DrawTask.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 1b4cd48ffc..3deb15a320 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -188,9 +188,10 @@ void DrawBounds::run(const SceneContextPointer& sceneContext, const RenderContex float numItems = (float) items.size(); float itemNum = 0.0f; for (const auto& item : items) { + glm::vec4 color(glm::vec3(itemNum / numItems), 1.0f); batch._glUniform3fv(_cornerLocation, 1, (const float*)(&item.bound.getCorner())); batch._glUniform3fv(_scaleLocation, 1, (const float*)(&item.bound.getScale())); - batch._glUniform4fv(_colorLocation, 1, (const float*)(&glm::vec4(glm::vec3(itemNum / numItems), 1.0f))); + batch._glUniform4fv(_colorLocation, 1, (const float*)(&color)); static const int NUM_VERTICES_PER_CUBE = 24; batch.draw(gpu::LINES, NUM_VERTICES_PER_CUBE, 0); From 5daf365784465c376a3702e9a04be6a125d4d873 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 11 Apr 2017 12:15:30 -0700 Subject: [PATCH 20/27] Avoiding warning maybe --- libraries/render/src/render/FilterTask.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render/src/render/FilterTask.cpp b/libraries/render/src/render/FilterTask.cpp index 76b42b0813..f1ab6b844a 100644 --- a/libraries/render/src/render/FilterTask.cpp +++ b/libraries/render/src/render/FilterTask.cpp @@ -78,7 +78,7 @@ void SelectSortItems::run(const SceneContextPointer& sceneContext, const RenderC indices.reserve(selectedItems.size()); // Collect - for (int srcIndex = 0; (srcIndex < inItems.size()) && (indices.size() < selectedItems.size()) ; srcIndex++ ) { + for (int srcIndex = 0; ((std::size_t) srcIndex < inItems.size()) && (indices.size() < selectedItems.size()) ; srcIndex++ ) { int index = selection.find(inItems[srcIndex].id); if (index != Selection::NOT_FOUND) { indices.emplace_back( Pair{ srcIndex, index } ); From e364b8d33e5ee01528b377a9904fc64d4945b80d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Apr 2017 13:35:59 -0700 Subject: [PATCH 21/27] avatar-mixer resends to avoid stale avatar --- .../src/avatars/AvatarMixerSlave.cpp | 21 ++++++++++++++----- libraries/avatars/src/AvatarData.h | 7 +++---- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index c4497a1066..a4e9b608de 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -175,6 +175,7 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { } }); + const uint64_t MIN_KEEP_ALIVE_PERIOD_FOR_OTHER_AVATAR = (AVATAR_UPDATE_TIMEOUT - 1) * USECS_PER_SECOND; AvatarSharedPointer thisAvatar = nodeData->getAvatarSharedPointer(); ViewFrustum cameraView = nodeData->getViewFrustom(); std::priority_queue sortedAvatars; @@ -262,11 +263,17 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // have 15 (45hz-30hz) duplicate frames. In this case, the stat // avg_other_av_skips_per_second does report 15. // - // make sure we haven't already sent this data from this sender to this receiver + // make sure we haven't already sent this data from this sender to that receiver // or that somehow we haven't sent if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { - ++numAvatarsHeldBack; - shouldIgnore = true; + // don't ignore this avatar if we haven't sent any update for a long while + uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(avatarNode->getUUID()); + const AvatarMixerClientData* otherNodeData = reinterpret_cast(avatarNode->getLinkedData()); + if (lastBroadcastTime > otherNodeData->getIdentityChangeTimestamp() && + lastBroadcastTime > startIgnoreCalculation - MIN_KEEP_ALIVE_PERIOD_FOR_OTHER_AVATAR) { + ++numAvatarsHeldBack; + shouldIgnore = true; + } } else if (lastSeqFromSender - lastSeqToReceiver > 1) { // this is a skip - we still send the packet but capture the presence of the skip so we see it happening ++numAvatarsWithSkippedFrames; @@ -302,8 +309,12 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); // If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO - // the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A. - if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) { + // the time that Avatar B flagged an IDENTITY DATA change + // or if no packet of any type has been sent for some time + // send IDENTITY DATA about Avatar B to Avatar A + uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(otherNode->getUUID()); + if (lastBroadcastTime <= otherNodeData->getIdentityChangeTimestamp() || + startAvatarDataPacking > lastBroadcastTime + MIN_KEEP_ALIVE_PERIOD_FOR_OTHER_AVATAR) { identityBytesSent += sendIdentityPacket(otherNodeData, node); } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 5ade0c448e..8319eb5249 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -110,6 +110,8 @@ const char LEFT_HAND_POINTING_FLAG = 1; const char RIGHT_HAND_POINTING_FLAG = 2; const char IS_FINGER_POINTING_FLAG = 4; +const qint64 AVATAR_UPDATE_TIMEOUT = 5 * USECS_PER_SECOND; + // AvatarData state flags - we store the details about the packet encoding in the first byte, // before the "header" structure const char AVATARDATA_FLAGS_MINIMUM = 0; @@ -599,10 +601,7 @@ public: } - bool shouldDie() const { - const qint64 AVATAR_SILENCE_THRESHOLD_USECS = 5 * USECS_PER_SECOND; - return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_SILENCE_THRESHOLD_USECS; - } + bool shouldDie() const { return _owningAvatarMixer.isNull() || getUsecsSinceLastUpdate() > AVATAR_UPDATE_TIMEOUT; } static const float OUT_OF_VIEW_PENALTY; From 63ea16f24b81a34e475e5b2e66f55b71348f1012 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Apr 2017 13:37:18 -0700 Subject: [PATCH 22/27] avatar-mixer to send identity packets as 'reliable' --- assignment-client/src/avatars/AvatarMixerSlave.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index a4e9b608de..56c15f7793 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -69,7 +69,7 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) { int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { int bytesSent = 0; QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); - auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size()); + auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size(), true, true); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious bytesSent += individualData.size(); identityPacket->write(individualData); From 14b60165efb5c5f6126a0c19eeee8a9c24461ae5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Apr 2017 14:55:08 -0700 Subject: [PATCH 23/27] don't keep stale avatars alive --- .../src/avatars/AvatarMixerSlave.cpp | 26 +++++++------------ 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index 56c15f7793..ee3282f82b 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -67,15 +67,13 @@ void AvatarMixerSlave::processIncomingPackets(const SharedNodePointer& node) { int AvatarMixerSlave::sendIdentityPacket(const AvatarMixerClientData* nodeData, const SharedNodePointer& destinationNode) { - int bytesSent = 0; QByteArray individualData = nodeData->getConstAvatarData()->identityByteArray(); - auto identityPacket = NLPacket::create(PacketType::AvatarIdentity, individualData.size(), true, true); individualData.replace(0, NUM_BYTES_RFC4122_UUID, nodeData->getNodeID().toRfc4122()); // FIXME, this looks suspicious - bytesSent += individualData.size(); - identityPacket->write(individualData); - DependencyManager::get()->sendPacket(std::move(identityPacket), *destinationNode); + auto identityPackets = NLPacketList::create(PacketType::AvatarIdentity, QByteArray(), true, true); + identityPackets->write(individualData); + DependencyManager::get()->sendPacketList(std::move(identityPackets), *destinationNode); _stats.numIdentityPackets++; - return bytesSent; + return individualData.size(); } static const int AVATAR_MIXER_BROADCAST_FRAMES_PER_SECOND = 45; @@ -175,7 +173,6 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { } }); - const uint64_t MIN_KEEP_ALIVE_PERIOD_FOR_OTHER_AVATAR = (AVATAR_UPDATE_TIMEOUT - 1) * USECS_PER_SECOND; AvatarSharedPointer thisAvatar = nodeData->getAvatarSharedPointer(); ViewFrustum cameraView = nodeData->getViewFrustom(); std::priority_queue sortedAvatars; @@ -263,17 +260,11 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // have 15 (45hz-30hz) duplicate frames. In this case, the stat // avg_other_av_skips_per_second does report 15. // - // make sure we haven't already sent this data from this sender to that receiver + // make sure we haven't already sent this data from this sender to this receiver // or that somehow we haven't sent if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { - // don't ignore this avatar if we haven't sent any update for a long while - uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(avatarNode->getUUID()); - const AvatarMixerClientData* otherNodeData = reinterpret_cast(avatarNode->getLinkedData()); - if (lastBroadcastTime > otherNodeData->getIdentityChangeTimestamp() && - lastBroadcastTime > startIgnoreCalculation - MIN_KEEP_ALIVE_PERIOD_FOR_OTHER_AVATAR) { - ++numAvatarsHeldBack; - shouldIgnore = true; - } + ++numAvatarsHeldBack; + shouldIgnore = true; } else if (lastSeqFromSender - lastSeqToReceiver > 1) { // this is a skip - we still send the packet but capture the presence of the skip so we see it happening ++numAvatarsWithSkippedFrames; @@ -312,9 +303,10 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // the time that Avatar B flagged an IDENTITY DATA change // or if no packet of any type has been sent for some time // send IDENTITY DATA about Avatar B to Avatar A + const uint64_t AVATAR_UPDATE_STALE = AVATAR_UPDATE_TIMEOUT - USECS_PER_SECOND; uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(otherNode->getUUID()); if (lastBroadcastTime <= otherNodeData->getIdentityChangeTimestamp() || - startAvatarDataPacking > lastBroadcastTime + MIN_KEEP_ALIVE_PERIOD_FOR_OTHER_AVATAR) { + startAvatarDataPacking > lastBroadcastTime + AVATAR_UPDATE_STALE) { identityBytesSent += sendIdentityPacket(otherNodeData, node); } From 5bdecfbfa0b59cf1406c73aa127d768d3799e6d9 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 13 Apr 2017 16:00:11 -0700 Subject: [PATCH 24/27] send keep-alive packets but don't resend identity --- .../src/avatars/AvatarMixerSlave.cpp | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index ee3282f82b..6e3dd150a4 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -263,8 +263,16 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { // make sure we haven't already sent this data from this sender to this receiver // or that somehow we haven't sent if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { - ++numAvatarsHeldBack; - shouldIgnore = true; + // don't ignore this avatar if we haven't sent any update for a long while + // in an effort to prevent other interfaces from deleting a stale avatar instance + uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(avatarNode->getUUID()); + const AvatarMixerClientData* otherNodeData = reinterpret_cast(avatarNode->getLinkedData()); + const uint64_t AVATAR_UPDATE_STALE = AVATAR_UPDATE_TIMEOUT - USECS_PER_SECOND; + if (lastBroadcastTime > otherNodeData->getIdentityChangeTimestamp() && + lastBroadcastTime + AVATAR_UPDATE_STALE > startIgnoreCalculation) { + ++numAvatarsHeldBack; + shouldIgnore = true; + } } else if (lastSeqFromSender - lastSeqToReceiver > 1) { // this is a skip - we still send the packet but capture the presence of the skip so we see it happening ++numAvatarsWithSkippedFrames; @@ -300,13 +308,8 @@ void AvatarMixerSlave::broadcastAvatarData(const SharedNodePointer& node) { const AvatarMixerClientData* otherNodeData = reinterpret_cast(otherNode->getLinkedData()); // If the time that the mixer sent AVATAR DATA about Avatar B to Avatar A is BEFORE OR EQUAL TO - // the time that Avatar B flagged an IDENTITY DATA change - // or if no packet of any type has been sent for some time - // send IDENTITY DATA about Avatar B to Avatar A - const uint64_t AVATAR_UPDATE_STALE = AVATAR_UPDATE_TIMEOUT - USECS_PER_SECOND; - uint64_t lastBroadcastTime = nodeData->getLastBroadcastTime(otherNode->getUUID()); - if (lastBroadcastTime <= otherNodeData->getIdentityChangeTimestamp() || - startAvatarDataPacking > lastBroadcastTime + AVATAR_UPDATE_STALE) { + // the time that Avatar B flagged an IDENTITY DATA change, send IDENTITY DATA about Avatar B to Avatar A. + if (nodeData->getLastBroadcastTime(otherNode->getUUID()) <= otherNodeData->getIdentityChangeTimestamp()) { identityBytesSent += sendIdentityPacket(otherNodeData, node); } From af5a352f0289d0072c0e64ebaca64c325b44620b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Fri, 14 Apr 2017 08:10:31 -0700 Subject: [PATCH 25/27] turn on handControllerGrab debug prints --- scripts/system/controllers/handControllerGrab.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/controllers/handControllerGrab.js b/scripts/system/controllers/handControllerGrab.js index d1c00a9d81..88d5229f1a 100644 --- a/scripts/system/controllers/handControllerGrab.js +++ b/scripts/system/controllers/handControllerGrab.js @@ -27,8 +27,8 @@ Script.include("/~/system/libraries/controllers.js"); // add lines where the hand ray picking is happening // -var WANT_DEBUG = false; -var WANT_DEBUG_STATE = false; +var WANT_DEBUG = true; +var WANT_DEBUG_STATE = true; var WANT_DEBUG_SEARCH_NAME = null; var FORCE_IGNORE_IK = false; From 7b48feca662b6f43bf2a641e5ab731c203c4d8ad Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 14 Apr 2017 11:53:11 -0700 Subject: [PATCH 26/27] address code review comments --- libraries/recording/src/recording/ClipCache.cpp | 3 ++- .../script-engine/src/RecordingScriptingInterface.cpp | 3 ++- .../script-engine/src/RecordingScriptingInterface.h | 1 - script-archive/acScripts/PlayRecordingOnAC.js | 2 ++ script-archive/acScripts/triggeredRecordingOnAC.js | 2 ++ script-archive/tests/playbackAcTest.js | 10 +++++++--- script-archive/vrShop/cash/shopCashierAC.js | 2 ++ script-archive/vrShop/review/shopReviewerAC.js | 2 +- scripts/developer/utilities/record/recorder.js | 2 ++ 9 files changed, 20 insertions(+), 7 deletions(-) diff --git a/libraries/recording/src/recording/ClipCache.cpp b/libraries/recording/src/recording/ClipCache.cpp index 0665608bad..5c55c6bb1c 100644 --- a/libraries/recording/src/recording/ClipCache.cpp +++ b/libraries/recording/src/recording/ClipCache.cpp @@ -10,6 +10,7 @@ #include "ClipCache.h" #include "impl/PointerClip.h" +#include "Logging.h" using namespace recording; NetworkClipLoader::NetworkClipLoader(const QUrl& url) : @@ -45,7 +46,7 @@ NetworkClipLoaderPointer ClipCache::getClipLoader(const QUrl& url) { } QSharedPointer ClipCache::createResource(const QUrl& url, const QSharedPointer& fallback, const void* extra) { - qDebug() << "Loading recording at" << url; + qCDebug(recordingLog) << "Loading recording at" << url; return QSharedPointer(new NetworkClipLoader(url), &Resource::deleter); } diff --git a/libraries/script-engine/src/RecordingScriptingInterface.cpp b/libraries/script-engine/src/RecordingScriptingInterface.cpp index e76a3859f0..36de1c1ef7 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.cpp +++ b/libraries/script-engine/src/RecordingScriptingInterface.cpp @@ -61,7 +61,8 @@ void RecordingScriptingInterface::loadRecording(const QString& url, QScriptValue auto weakClipLoader = clipLoader.toWeakRef(); // when clip loaded, call the callback with the URL and success boolean - connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, this, [this, weakClipLoader, url, callback]() mutable { + connect(clipLoader.data(), &recording::NetworkClipLoader::clipLoaded, this, + [this, weakClipLoader, url, callback]() mutable { if (auto clipLoader = weakClipLoader.toStrongRef()) { qCDebug(scriptengine) << "Loaded recording from" << url; diff --git a/libraries/script-engine/src/RecordingScriptingInterface.h b/libraries/script-engine/src/RecordingScriptingInterface.h index f6d335b17d..a9fdf1deb4 100644 --- a/libraries/script-engine/src/RecordingScriptingInterface.h +++ b/libraries/script-engine/src/RecordingScriptingInterface.h @@ -31,7 +31,6 @@ public: void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; } public slots: - void loadRecording(const QString& url, QScriptValue callback = QScriptValue()); void startPlaying(); diff --git a/script-archive/acScripts/PlayRecordingOnAC.js b/script-archive/acScripts/PlayRecordingOnAC.js index 015f247e4a..5979913d23 100644 --- a/script-archive/acScripts/PlayRecordingOnAC.js +++ b/script-archive/acScripts/PlayRecordingOnAC.js @@ -23,6 +23,8 @@ Agent.isAvatar = true; Recording.loadRecording(recordingFile, function(success) { if (success) { Script.update.connect(update); + } else { + print("Failed to load recording from " + recordingFile); } }); diff --git a/script-archive/acScripts/triggeredRecordingOnAC.js b/script-archive/acScripts/triggeredRecordingOnAC.js index c3a87bc44e..964e82321f 100644 --- a/script-archive/acScripts/triggeredRecordingOnAC.js +++ b/script-archive/acScripts/triggeredRecordingOnAC.js @@ -47,6 +47,8 @@ var playRecording = function() { Recording.startPlaying(); isPlaying = true; isPlayable = false; // Set this true again after the cooldown period + } else { + print("Failed to load recording from " + CLIP_URL); } }); }; diff --git a/script-archive/tests/playbackAcTest.js b/script-archive/tests/playbackAcTest.js index 51ff1bdf02..5439f6f474 100644 --- a/script-archive/tests/playbackAcTest.js +++ b/script-archive/tests/playbackAcTest.js @@ -10,9 +10,13 @@ Agent.isAvatar = true; Script.setTimeout(function () { Avatar.position = origin; - Recording.loadRecording("d:/hifi.rec", function(success){ - Recording.setPlayerLoop(true); - Recording.startPlaying(); + Recording.loadRecording("d:/hifi.rec", function(success) { + if (success) { + Recording.setPlayerLoop(true); + Recording.startPlaying(); + } else { + print("Failed to load recording"); + } }); }, millisecondsToWaitBeforeStarting); diff --git a/script-archive/vrShop/cash/shopCashierAC.js b/script-archive/vrShop/cash/shopCashierAC.js index 91b45484fd..5236fa1218 100644 --- a/script-archive/vrShop/cash/shopCashierAC.js +++ b/script-archive/vrShop/cash/shopCashierAC.js @@ -60,6 +60,8 @@ function update(deltaTime) { Recording.setPlayerUseHeadModel(false); Recording.setPlayerUseSkeletonModel(useAvatarModel); Agent.isAvatar = true; + } else { + print("Failed to load recording from " + clip_url); } }); } diff --git a/script-archive/vrShop/review/shopReviewerAC.js b/script-archive/vrShop/review/shopReviewerAC.js index c39aaa2f4a..47b08e0a85 100644 --- a/script-archive/vrShop/review/shopReviewerAC.js +++ b/script-archive/vrShop/review/shopReviewerAC.js @@ -49,7 +49,7 @@ function getAction(channel, message, senderID) { case SHOW: print("Show"); - Recording.loadRecording(clip_url, function(success){ + Recording.loadRecording(clip_url, function(success) { if (success) { Agent.isAvatar = true; Recording.setPlayerTime(0.0); diff --git a/scripts/developer/utilities/record/recorder.js b/scripts/developer/utilities/record/recorder.js index b335274372..bda4edc125 100644 --- a/scripts/developer/utilities/record/recorder.js +++ b/scripts/developer/utilities/record/recorder.js @@ -284,6 +284,8 @@ function mousePressEvent(event) { Recording.loadRecording(recordingFile, function(success) { if (success) { setDefaultPlayerOptions(); + } else { + print("Failed to load recording from " + recordingFile); } }); } From 891d52909e5fcca4bf1dfc65f5af7032a4b21303 Mon Sep 17 00:00:00 2001 From: kunalgosar Date: Fri, 14 Apr 2017 14:10:19 -0700 Subject: [PATCH 27/27] fixed typo in comments --- scripts/system/fingerPaint.js | 2 +- tutorial/tutorial.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/system/fingerPaint.js b/scripts/system/fingerPaint.js index ec3c8af3d9..88245503e8 100644 --- a/scripts/system/fingerPaint.js +++ b/scripts/system/fingerPaint.js @@ -450,7 +450,7 @@ } /** - * A controller in made up of parts, and each part can have multiple "layers," + * A controller is made up of parts, and each part can have multiple "layers," * which are really just different texures. For example, the "trigger" part * has "normal" and "highlight" layers. */ diff --git a/tutorial/tutorial.js b/tutorial/tutorial.js index 26fa51e896..97528b9b3b 100644 --- a/tutorial/tutorial.js +++ b/tutorial/tutorial.js @@ -118,7 +118,7 @@ function findEntitiesWithTag(tag) { } /** - * A controller in made up of parts, and each part can have multiple "layers," + * A controller is made up of parts, and each part can have multiple "layers," * which are really just different texures. For example, the "trigger" part * has "normal" and "highlight" layers. */