From 2d2722bfc500a2bec809732fd54571cf6ba60431 Mon Sep 17 00:00:00 2001 From: Olivier Prat Date: Thu, 13 Jul 2017 11:05:04 +0200 Subject: [PATCH] Added async transition query on scene --- interface/src/avatar/AvatarManager.cpp | 9 +- interface/src/ui/overlays/Overlays.cpp | 2 +- .../src/avatars-renderer/Avatar.cpp | 29 ++--- .../src/avatars-renderer/Avatar.h | 5 +- libraries/render-utils/src/FadeEffect.cpp | 23 +--- libraries/render-utils/src/FadeEffect.h | 2 +- libraries/render/src/render/Scene.cpp | 113 ++++++++++-------- libraries/render/src/render/Scene.h | 51 +++++--- libraries/render/src/render/Transition.h | 2 +- 9 files changed, 122 insertions(+), 114 deletions(-) diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 7aa2f4b78d..5c2da8e0e5 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -282,10 +282,11 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { const render::ScenePointer& scene = qApp->getMain3DScene(); while (avatarItr != _avatarsToFade.end()) { auto avatar = std::static_pointer_cast(*avatarItr); - // TEMP OP avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); - // TEMP OP avatar->animateScaleChanges(deltaTime); - // TEMP OP if (avatar->getTargetScale() <= MIN_FADE_SCALE) { - if (!avatar->isFading(scene)) { + // avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); + // avatar->animateScaleChanges(deltaTime); + // if (avatar->getTargetScale() <= MIN_FADE_SCALE) { + avatar->updateFadingStatus(scene); + if (!avatar->isFading()) { // fading to zero is such a rare event we push a unique transaction for each if (avatar->isInScene()) { render::Transaction transaction; diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 72682fcb8c..6190027b05 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -96,7 +96,7 @@ void Overlays::cleanupOverlaysToDelete() { } while (!_overlaysToDelete.isEmpty()); } - if (transaction._removedItems.size() > 0) { + if (transaction.hasRemovedItems()) { scene->enqueueTransaction(transaction); } } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 7ad2dd219d..58ee6782fd 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -498,15 +498,6 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc _mustFadeIn = true; } -bool Avatar::isFading(render::ScenePointer scene) const { - if (isInScene()) { - const auto& item = scene->getItem(_renderItemID); - auto transitionId = item.getTransitionId(); - return _isWaitingForFade || transitionId!= render::TransitionStage::INVALID_INDEX; - } - return _isWaitingForFade; -} - void Avatar::fadeIn(render::ScenePointer scene) { render::Transaction transaction; fade(transaction, render::Transition::USER_ENTER_DOMAIN); @@ -534,7 +525,17 @@ void Avatar::fade(render::Transaction& transaction, render::Transition::Type typ transaction.addTransitionToItem(itemId, type, _renderItemID); } } - _isWaitingForFade = true; + _isFading = true; +} + +void Avatar::updateFadingStatus(render::ScenePointer scene) { + render::Transaction transaction; + transaction.queryTransitionOnItem(_renderItemID, [this](render::ItemID id, const render::Transition* transition) { + if (transition == nullptr || transition->isFinished) { + _isFading = false; + } + }); + scene->enqueueTransaction(transaction); } void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) { @@ -712,14 +713,6 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { _mustFadeIn = false; } - if (isInScene()) { - const auto& item = scene->getItem(_renderItemID); - auto transitionId = item.getTransitionId(); - if (_isWaitingForFade && transitionId != render::TransitionStage::INVALID_INDEX) { - _isWaitingForFade = false; - } - } - for (auto attachmentModelToRemove : _attachmentsToRemove) { attachmentModelToRemove->removeFromScene(scene, transaction); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index b1a7c48bfb..10710bd631 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -252,7 +252,8 @@ public: void fadeIn(render::ScenePointer scene); void fadeOut(render::ScenePointer scene, KillAvatarReason reason); - bool isFading(render::ScenePointer scene) const; + bool isFading() const { return _isFading; } + void updateFadingStatus(render::ScenePointer scene); public slots: @@ -356,7 +357,7 @@ private: bool _isLookAtTarget { false }; bool _isAnimatingScale { false }; bool _mustFadeIn{ false }; - bool _isWaitingForFade{ false }; + bool _isFading{ false }; static int _jointConesID; diff --git a/libraries/render-utils/src/FadeEffect.cpp b/libraries/render-utils/src/FadeEffect.cpp index 3131944c90..222224ed5f 100644 --- a/libraries/render-utils/src/FadeEffect.cpp +++ b/libraries/render-utils/src/FadeEffect.cpp @@ -548,8 +548,6 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou auto transitionStage = scene->getStage(render::TransitionStage::getName()); uint64_t now = usecTimestampNow(); const double deltaTime = (int64_t(now) - int64_t(_previousTime)) / double(USECS_PER_SECOND); - render::Transaction transaction; - bool hasTransactions = false; bool isFirstItem = true; output = (FadeConfig::Category) jobConfig->editedCategory; @@ -557,21 +555,12 @@ void FadeJob::run(const render::RenderContextPointer& renderContext, FadeJob::Ou // And now update fade effect for (auto transitionId : *transitionStage) { auto& state = transitionStage->editTransition(transitionId); - if (!update(*jobConfig, scene, state, deltaTime)) { - // Remove transition for this item - transaction.addTransitionToItem(state.itemId, render::Transition::NONE); - hasTransactions = true; - } - + update(*jobConfig, scene, state, deltaTime); if (isFirstItem) { jobConfig->setProperty("threshold", state.threshold); isFirstItem = false; } } - - if (hasTransactions) { - scene->enqueueTransaction(transaction); - } _previousTime = now; } @@ -585,13 +574,12 @@ const FadeConfig::Category FadeJob::transitionToCategory[render::Transition::TYP FadeConfig::AVATAR_CHANGE }; -bool FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const { +void FadeJob::update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const { const auto fadeCategory = transitionToCategory[transition.eventType]; auto& eventConfig = config.events[fadeCategory]; auto& item = scene->getItem(transition.itemId); const double eventDuration = (double)eventConfig.duration; const FadeConfig::Timing timing = (FadeConfig::Timing) eventConfig.timing; - bool continueTransition = true; if (item.exist()) { auto aabb = item.getBound(); @@ -619,7 +607,7 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re transition.baseInvSize.x = 1.f / dimensions.x; transition.baseInvSize.y = 1.f / dimensions.y; transition.baseInvSize.z = 1.f / dimensions.z; - continueTransition = transition.threshold < 1.f; + transition.isFinished = transition.threshold >= 1.f; if (transition.eventType == render::Transition::ELEMENT_ENTER_DOMAIN) { transition.threshold = 1.f - transition.threshold; } @@ -655,7 +643,7 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re transition.threshold = computeElementEnterRatio(transition.time, eventConfig.duration, timing); transition.baseOffset = transition.noiseOffset - dimensions.y / 2.f; transition.baseInvSize.y = 1.f / dimensions.y; - continueTransition = transition.threshold < 1.f; + transition.isFinished = transition.threshold >= 1.f; if (transition.eventType == render::Transition::USER_LEAVE_DOMAIN) { transition.threshold = 1.f - transition.threshold; } @@ -671,10 +659,9 @@ bool FadeJob::update(const Config& config, const render::ScenePointer& scene, re } transition.noiseOffset += eventConfig.noiseSpeed * (float)transition.time; + transition.threshold = std::max(0.f, std::min(1.f, transition.threshold)); transition.threshold = (transition.threshold - 0.5f)*_thresholdScale[fadeCategory] + 0.5f; transition.time += deltaTime; - - return continueTransition; } float FadeJob::computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing) { diff --git a/libraries/render-utils/src/FadeEffect.h b/libraries/render-utils/src/FadeEffect.h index 242e05ef72..431a069ee6 100644 --- a/libraries/render-utils/src/FadeEffect.h +++ b/libraries/render-utils/src/FadeEffect.h @@ -236,7 +236,7 @@ private: float _thresholdScale[FadeConfig::CATEGORY_COUNT]; uint64_t _previousTime{ 0 }; - bool update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const; + void update(const Config& config, const render::ScenePointer& scene, render::Transition& transition, const double deltaTime) const; static float computeElementEnterRatio(double time, const double period, FadeConfig::Timing timing); const render::Item* findNearestItem(const render::RenderContextPointer& renderContext, const render::Varying& input, float& minIsectDistance) const; diff --git a/libraries/render/src/render/Scene.cpp b/libraries/render/src/render/Scene.cpp index 01829d8216..18aef8ff70 100644 --- a/libraries/render/src/render/Scene.cpp +++ b/libraries/render/src/render/Scene.cpp @@ -19,8 +19,7 @@ using namespace render; void Transaction::resetItem(ItemID id, const PayloadPointer& payload) { if (payload) { - _resetItems.emplace_back(id); - _resetPayloads.emplace_back(payload); + _resetItems.emplace_back(Reset{ id, payload }); } else { qCDebug(renderlogging) << "WARNING: Transaction::resetItem with a null payload!"; removeItem(id); @@ -32,20 +31,19 @@ void Transaction::removeItem(ItemID id) { } void Transaction::addTransitionToItem(ItemID id, Transition::Type transition, ItemID boundId) { - _transitioningItems.emplace_back(id); - _transitioningItemBounds.emplace_back(boundId); - _transitionTypes.emplace_back(transition); + _addedTransitions.emplace_back(TransitionAdd{ id, transition, boundId }); } void Transaction::removeTransitionFromItem(ItemID id) { - _transitioningItems.emplace_back(id); - _transitioningItemBounds.emplace_back(render::Item::INVALID_ITEM_ID); - _transitionTypes.emplace_back(render::Transition::NONE); + _addedTransitions.emplace_back(TransitionAdd{ id, Transition::NONE, render::Item::INVALID_ITEM_ID }); +} + +void Transaction::queryTransitionOnItem(ItemID id, TransitionQueryFunc func) { + _queriedTransitions.emplace_back(TransitionQuery{ id, func }); } void Transaction::updateItem(ItemID id, const UpdateFunctorPointer& functor) { - _updatedItems.emplace_back(id); - _updateFunctors.emplace_back(functor); + _updatedItems.emplace_back(Update{ id, functor }); } void Transaction::resetSelection(const Selection& selection) { @@ -54,14 +52,11 @@ void Transaction::resetSelection(const Selection& selection) { void Transaction::merge(const Transaction& transaction) { _resetItems.insert(_resetItems.end(), transaction._resetItems.begin(), transaction._resetItems.end()); - _resetPayloads.insert(_resetPayloads.end(), transaction._resetPayloads.begin(), transaction._resetPayloads.end()); _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()); - _transitioningItems.insert(_transitioningItems.end(), transaction._transitioningItems.begin(), transaction._transitioningItems.end()); - _transitioningItemBounds.insert(_transitioningItemBounds.end(), transaction._transitioningItemBounds.begin(), transaction._transitioningItemBounds.end()); - _transitionTypes.insert(_transitionTypes.end(), transaction._transitionTypes.begin(), transaction._transitionTypes.end()); + _addedTransitions.insert(_addedTransitions.end(), transaction._addedTransitions.begin(), transaction._addedTransitions.end()); + _queriedTransitions.insert(_queriedTransitions.end(), transaction._queriedTransitions.begin(), transaction._queriedTransitions.end()); } @@ -120,19 +115,21 @@ void Scene::processTransactionQueue() { // capture anything coming from the transaction // resets and potential NEW items - resetItems(consolidatedTransaction._resetItems, consolidatedTransaction._resetPayloads); + resetItems(consolidatedTransaction._resetItems); // Update the numItemsAtomic counter AFTER the reset changes went through _numAllocatedItems.exchange(maxID); // updates - updateItems(consolidatedTransaction._updatedItems, consolidatedTransaction._updateFunctors); + updateItems(consolidatedTransaction._updatedItems); // removes removeItems(consolidatedTransaction._removedItems); - // Transitions - transitionItems(consolidatedTransaction._transitioningItems, consolidatedTransaction._transitionTypes, consolidatedTransaction._transitioningItemBounds); + // add transitions + transitionItems(consolidatedTransaction._addedTransitions); + + queryTransitionItems(consolidatedTransaction._queriedTransitions); // Update the numItemsAtomic counter AFTER the pending changes went through _numAllocatedItems.exchange(maxID); @@ -146,34 +143,31 @@ void Scene::processTransactionQueue() { } } -void Scene::resetItems(const ItemIDs& ids, Payloads& payloads) { - auto resetPayload = payloads.begin(); - for (auto resetID : ids) { +void Scene::resetItems(const Transaction::Resets& transactions) { + for (auto& reset : transactions) { // Access the true item - auto& item = _items[resetID]; + auto itemId = std::get<0>(reset); + auto& item = _items[itemId]; auto oldKey = item.getKey(); auto oldCell = item.getCell(); // Reset the item with a new payload - item.resetPayload(*resetPayload); + item.resetPayload(std::get<1>(reset)); auto newKey = item.getKey(); // Update the item's container assert((oldKey.isSpatial() == newKey.isSpatial()) || oldKey._flags.none()); if (newKey.isSpatial()) { - auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), resetID, newKey); + auto newCell = _masterSpatialTree.resetItem(oldCell, oldKey, item.getBound(), itemId, newKey); item.resetCell(newCell, newKey.isSmall()); } else { - _masterNonspatialSet.insert(resetID); + _masterNonspatialSet.insert(itemId); } - - // next loop - resetPayload++; } } -void Scene::removeItems(const ItemIDs& ids) { - for (auto removedID :ids) { +void Scene::removeItems(const Transaction::Removes& transactions) { + for (auto removedID : transactions) { // Access the true item auto& item = _items[removedID]; auto oldCell = item.getCell(); @@ -197,12 +191,10 @@ void Scene::removeItems(const ItemIDs& ids) { } } -void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) { - - auto updateFunctor = functors.begin(); - for (auto updateID : ids) { +void Scene::updateItems(const Transaction::Updates& transactions) { + for (auto& update : transactions) { + auto updateID = std::get<0>(update); if (updateID == Item::INVALID_ITEM_ID) { - updateFunctor++; continue; } @@ -212,7 +204,7 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) { auto oldKey = item.getKey(); // Update the item - item.update((*updateFunctor)); + item.update(std::get<1>(update)); auto newKey = item.getKey(); // Update the item's container @@ -234,39 +226,54 @@ void Scene::updateItems(const ItemIDs& ids, UpdateFunctors& functors) { _masterNonspatialSet.insert(updateID); } } - - - // next loop - updateFunctor++; } } -void Scene::transitionItems(const ItemIDs& ids, const TransitionTypes& types, const ItemIDs& boundIds) { - auto transitionType = types.begin(); - auto boundId = boundIds.begin(); +void Scene::transitionItems(const Transaction::TransitionAdds& transactions) { auto transitionStage = getStage(TransitionStage::getName()); - for (auto itemId : ids) { + for (auto& add : transactions) { + auto itemId = std::get<0>(add); // Access the true item const auto& item = _items[itemId]; if (item.exist()) { auto transitionId = INVALID_INDEX; + auto transitionType = std::get<1>(add); + auto boundId = std::get<2>(add); // Remove pre-existing transition, if need be - if (item.getTransitionId() != render::TransitionStage::INVALID_INDEX) { + if (TransitionStage::isIndexInvalid(item.getTransitionId())) { transitionStage->removeTransition(item.getTransitionId()); } // Add a new one. - if (*transitionType != Transition::NONE) { - transitionId = transitionStage->addTransition(itemId, *transitionType, *boundId); + if (transitionType != Transition::NONE) { + transitionId = transitionStage->addTransition(itemId, transitionType, boundId); } setItemTransition(itemId, transitionId); } + } +} - // next loop - transitionType++; - boundId++; +void Scene::queryTransitionItems(const Transaction::TransitionQueries& transactions) { + auto transitionStage = getStage(TransitionStage::getName()); + + for (auto& query : transactions) { + auto itemId = std::get<0>(query); + // Access the true item + const auto& item = _items[itemId]; + auto func = std::get<1>(query); + if (item.exist() && func != nullptr) { + auto transitionId = item.getTransitionId(); + + if (TransitionStage::isIndexInvalid(transitionId)) { + auto& transition = transitionStage->getTransition(transitionId); + func(itemId, &transition); + } + else { + func(itemId, nullptr); + } + } } } @@ -325,8 +332,8 @@ Selection Scene::getSelection(const Selection::Name& name) const { } } -void Scene::resetSelections(const Selections& selections) { - for (auto selection : selections) { +void Scene::resetSelections(const Transaction::SelectionResets& transactions) { + for (auto selection : transactions) { auto found = _selections.find(selection.getName()); if (found == _selections.end()) { _selections.insert(SelectionMap::value_type(selection.getName(), selection)); diff --git a/libraries/render/src/render/Scene.h b/libraries/render/src/render/Scene.h index aea006394b..b24cde240f 100644 --- a/libraries/render/src/render/Scene.h +++ b/libraries/render/src/render/Scene.h @@ -21,6 +21,7 @@ namespace render { class Engine; +class Scene; // Transaction is the mechanism to make any change to the scene. // Whenever a new item need to be reset, @@ -32,16 +33,22 @@ class Engine; // of updating the scene before it s rendered. // class Transaction { + friend class Scene; public: + + typedef std::function TransitionQueryFunc; + Transaction() {} ~Transaction() {} // Item transactions void resetItem(ItemID id, const PayloadPointer& payload); void removeItem(ItemID id); + bool hasRemovedItems() const { return !_removedItems.empty(); } void addTransitionToItem(ItemID id, Transition::Type transition, ItemID boundId = render::Item::INVALID_ITEM_ID); void removeTransitionFromItem(ItemID id); + void queryTransitionOnItem(ItemID id, TransitionQueryFunc func); template void updateItem(ItemID id, std::function func) { updateItem(id, std::make_shared>(func)); @@ -58,18 +65,28 @@ public: // 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; - ItemIDs _transitioningItems; - ItemIDs _transitioningItemBounds; - TransitionTypes _transitionTypes; - UpdateFunctors _updateFunctors; - - Selections _resetSelections; - protected: + + using Reset = std::tuple; + using Remove = ItemID; + using Update = std::tuple; + using TransitionAdd = std::tuple; + using TransitionQuery = std::tuple; + using SelectionReset = Selection; + + using Resets = std::vector; + using Removes = std::vector; + using Updates = std::vector; + using TransitionAdds = std::vector; + using TransitionQueries = std::vector; + using SelectionResets = std::vector; + + Resets _resetItems; + Removes _removedItems; + Updates _updatedItems; + TransitionAdds _addedTransitions; + TransitionQueries _queriedTransitions; + SelectionResets _resetSelections; }; typedef std::queue TransactionQueue; @@ -134,6 +151,7 @@ public: void resetItemTransition(ItemID id); protected: + // Thread safe elements that can be accessed from anywhere std::atomic _IDAllocator{ 1 }; // first valid itemID will be One std::atomic _numAllocatedItems{ 1 }; // num of allocated items, matching the _items.size() @@ -147,10 +165,11 @@ protected: ItemSpatialTree _masterSpatialTree; ItemIDSet _masterNonspatialSet; - void resetItems(const ItemIDs& ids, Payloads& payloads); - void removeItems(const ItemIDs& ids); - void updateItems(const ItemIDs& ids, UpdateFunctors& functors); - void transitionItems(const ItemIDs& ids, const TransitionTypes& types, const ItemIDs& boundIds); + void resetItems(const Transaction::Resets& transactions); + void removeItems(const Transaction::Removes& transactions); + void updateItems(const Transaction::Updates& transactions); + void transitionItems(const Transaction::TransitionAdds& transactions); + void queryTransitionItems(const Transaction::TransitionQueries& transactions); void collectSubItems(ItemID parentId, ItemIDs& subItems) const; @@ -158,7 +177,7 @@ protected: mutable std::mutex _selectionsMutex; // mutable so it can be used in the thread safe getSelection const method SelectionMap _selections; - void resetSelections(const Selections& selections); + void resetSelections(const Transaction::SelectionResets& transactions); // More actions coming to selections soon: // void removeFromSelection(const Selection& selection); // void appendToSelection(const Selection& selection); diff --git a/libraries/render/src/render/Transition.h b/libraries/render/src/render/Transition.h index 20efe524cf..a87595e4ce 100644 --- a/libraries/render/src/render/Transition.h +++ b/libraries/render/src/render/Transition.h @@ -41,7 +41,7 @@ namespace render { glm::vec3 baseOffset{ 0.f, 0.f, 0.f }; glm::vec3 baseInvSize{ 1.f, 1.f, 1.f }; float threshold{ 0.f }; - + bool isFinished{ false }; }; typedef std::shared_ptr TransitionPointer;