diff options
Diffstat (limited to 'src/Runtime/ogl-runtime/src/runtime/Qt3DSActivationManager.cpp')
m--------- | src/Runtime/ogl-runtime | 0 | ||||
-rw-r--r-- | src/Runtime/ogl-runtime/src/runtime/Qt3DSActivationManager.cpp | 1027 |
2 files changed, 0 insertions, 1027 deletions
diff --git a/src/Runtime/ogl-runtime b/src/Runtime/ogl-runtime new file mode 160000 +Subproject 427fddb50d43aa21a90fc7356ee3cdd8a908df5 diff --git a/src/Runtime/ogl-runtime/src/runtime/Qt3DSActivationManager.cpp b/src/Runtime/ogl-runtime/src/runtime/Qt3DSActivationManager.cpp deleted file mode 100644 index 3d052742..00000000 --- a/src/Runtime/ogl-runtime/src/runtime/Qt3DSActivationManager.cpp +++ /dev/null @@ -1,1027 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2013 NVIDIA Corporation. -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt 3D Studio. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include "RuntimePrefix.h" -#include "Qt3DSActivationManager.h" -#include "Qt3DSElementSystem.h" -#include "Qt3DSComponentManager.h" -#include "foundation/Qt3DSFlags.h" -#include "foundation/Qt3DSContainers.h" -#include "foundation/Qt3DSInvasiveSet.h" -#include "foundation/Qt3DSInvasiveLinkedList.h" -#include "foundation/Qt3DSAtomic.h" -#include "foundation/Qt3DSBroadcastingAllocator.h" -#include "foundation/StringTable.h" -#include "EASTL/sort.h" -#include "Qt3DSAttributeHashes.h" -#include "Qt3DSPresentation.h" -#include "foundation/Qt3DSPerfTimer.h" -#include "foundation/Qt3DSMutex.h" -#include "foundation/Qt3DSSync.h" -#include "Qt3DSRenderThreadPool.h" - -using namespace qt3ds::runtime; -using namespace qt3ds::runtime::element; -using qt3ds::render::IThreadPool; -using qt3ds::foundation::Time; - -namespace { - -typedef nvvector<TElementAndSortKey> TElementAndSortKeyList; - -struct STimeEvent -{ - enum Type { - Start = 0, - Stop, - }; - - Type m_Type; - TTimeUnit m_Time; - nvvector<SElement *> m_AffectedNodes; - - STimeEvent(Type inType, NVAllocatorCallback &alloc, TTimeUnit inTime) - : m_Type(inType) - , m_Time(inTime) - , m_AffectedNodes(alloc, "TimeEvent") - { - } - - void Reset() - { - m_Time = 0; - m_AffectedNodes.clear(); - } -}; - -struct STimeEventGreaterThan -{ - bool operator()(const STimeEvent *lhs, const STimeEvent *rhs) const - { - if (lhs->m_Time == rhs->m_Time) - return lhs->m_Type > rhs->m_Type; - - return lhs->m_Time > rhs->m_Time; - } -}; - -struct STimeEventLessThan -{ - bool operator()(const STimeEvent *lhs, const STimeEvent *rhs) const - { - if (lhs->m_Time == rhs->m_Time) - return lhs->m_Type < rhs->m_Type; - - return lhs->m_Time < rhs->m_Time; - } -}; - -typedef nvvector<STimeEvent *> TTimeEventList; -struct STimeContext; -typedef NVDataRef<NVScopedRefCounted<STimeContext>> TTimeContextSet; - -// Tree navigation - -SElement *GetElementNodeFirstChild(SElement &inNode) -{ - return inNode.m_Child; -} -SElement *GetElementNodeNextSibling(SElement &inNode) -{ - return inNode.m_Sibling; -} -SElement *GetElementNodeParent(SElement &inNode) -{ - return inNode.m_Parent; -} - -struct SScanBufferEntry -{ - SElement *m_Node; - QT3DSU32 m_StartTime; - QT3DSU32 m_EndTime; - - SScanBufferEntry() - : m_Node(NULL) - , m_StartTime(0) - , m_EndTime(QT3DS_MAX_U32) - { - } - SScanBufferEntry(SElement *inNode) - : m_Node(inNode) - , m_StartTime(0) - , m_EndTime(QT3DS_MAX_U32) - { - } - SScanBufferEntry(SElement *inNode, QT3DSU32 start, QT3DSU32 end) - : m_Node(inNode) - , m_StartTime(start) - , m_EndTime(end) - { - } - - SScanBufferEntry(SElement *inNode, bool inParentActive) - : m_Node(inNode) - , m_StartTime(inParentActive ? 1 : 0) - , m_EndTime(0) - { - } - - bool IsParentActive() const { return m_StartTime ? true : false; } -}; - -typedef nvvector<SScanBufferEntry> TScanBuffer; -typedef nvvector<SElement *> TElementNodePtrList; - -struct SElementIndexPairSorter -{ - bool operator()(const eastl::pair<element::SElement *, QT3DSU32> &lhs, - const eastl::pair<element::SElement *, QT3DSU32> &rhs) const - { - return lhs.second < rhs.second; - } -}; - -struct SElementPtrSort -{ - bool operator()(const SElement *lhs, const SElement *rhs) - { - return lhs->Depth() < rhs->Depth(); - } -}; - -DEFINE_INVASIVE_SINGLE_LIST(TimeContext); - -struct STimeContext -{ - NVAllocatorCallback &m_Allocator; - SComponent &m_Component; - CTimePolicy m_TimePolicy; - SComponentTimePolicyOverride *m_TimePolicyOverride; - TTimeUnit m_CurrentTime; - TElementNodePtrList m_Elements; - TTimeEventList m_TimeEventBackingStore; - TTimeEventList m_TimeEvents; - SActivationManagerNodeDirtyList m_DirtyList; - QT3DSU32 m_TimeEventBackingStoreIndex; - QT3DSI32 mRefCount; - STimeContext *m_NextSibling; - TTimeContextList m_Children; - Mutex &m_ElementAccessMutex; - bool m_AllNodesDirty; - bool m_TimeDataNeedsUpdate; - - STimeContext(NVAllocatorCallback &alloc, SComponent &inComponent, Mutex &inElementAccessMutex) - : m_Allocator(alloc) - , m_Component(inComponent) - , m_TimePolicyOverride(NULL) - , m_CurrentTime(-1) - , m_Elements(alloc, "m_Elements") - , m_TimeEventBackingStore(alloc, "TimeEventBackingStore") - , m_TimeEvents(alloc, "TimeEvents") - , m_DirtyList(alloc) - , m_TimeEventBackingStoreIndex(0) - , mRefCount(0) - , m_NextSibling(NULL) - , m_ElementAccessMutex(inElementAccessMutex) - , m_AllNodesDirty(true) - , m_TimeDataNeedsUpdate(true) - { - } - - QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Allocator) - ~STimeContext() - { - Reset(); - for (TTimeEventList::iterator iter = m_TimeEventBackingStore.begin(), - end = m_TimeEventBackingStore.end(); - iter != end; ++iter) { - NVDelete(m_Allocator, *iter); - } - - m_TimeEventBackingStore.clear(); - RemoveOverride(); - } - - void Reset() - { - for (TTimeEventList::iterator iter = m_TimeEvents.begin(), end = m_TimeEvents.end(); - iter != end; ++iter) - (*iter)->Reset(); - - m_TimeEvents.clear(); - m_TimeEventBackingStoreIndex = 0; - m_CurrentTime = -1; - m_DirtyList.clear(); - m_AllNodesDirty = true; - m_TimeDataNeedsUpdate = true; - } - - STimeEvent &GetTimeEventForTime(TTimeUnit inTime, STimeEvent::Type inType) - { - TTimeEventList::iterator inserter = m_TimeEvents.end(); - for (TTimeEventList::iterator iter = m_TimeEvents.begin(), end = m_TimeEvents.end(); - iter != end && inserter == end; ++iter) { - if ((*iter)->m_Time == inTime) { - if ((*iter)->m_Type == inType) - return **iter; - // Start comes before stop - if ((*iter)->m_Type == STimeEvent::Stop) - inserter = iter; - } - - if ((*iter)->m_Time > inTime) - inserter = iter; - } - - if (m_TimeEventBackingStoreIndex == m_TimeEventBackingStore.size()) - m_TimeEventBackingStore.push_back( - QT3DS_NEW(m_Allocator, STimeEvent)(inType, m_Allocator, inTime)); - - STimeEvent *newEvent = m_TimeEventBackingStore[m_TimeEventBackingStoreIndex]; - ++m_TimeEventBackingStoreIndex; - - newEvent->m_Time = inTime; - newEvent->m_Type = inType; - newEvent->m_AffectedNodes.clear(); - - if (inserter == m_TimeEvents.end()) - m_TimeEvents.push_back(newEvent); - else - m_TimeEvents.insert(inserter, newEvent); - - return *newEvent; - }; - - void UpdateNodeList(nvvector<SElement *> &inList, bool timeActive) - { - for (QT3DSU32 elemIdx = 0, endIdx = inList.size(); elemIdx < endIdx; ++elemIdx) { - SActivationManagerNode &theNode = inList[elemIdx]->m_ActivationManagerNode; - if (timeActive != theNode.m_Flags.IsTimeActive()) { - theNode.m_Flags.SetTimeActive(timeActive); - SetElementDirty(*inList[elemIdx]); - } - } - } - - // Returns true if we have reached the end time. - bool CalculateNewTime(TTimeUnit inGlobalTime) - { - Option<TTimeUnit> theNewTime; - if (m_TimePolicyOverride) { - SComponentTimePolicyOverride *theOverride = m_TimePolicyOverride; - eastl::pair<Q3DStudio::BOOL, TTimeUnit> theEvalResult = - theOverride->ComputeLocalTime(m_TimePolicy, inGlobalTime); - if (theEvalResult.first && theOverride->m_TimeCallback) { - Mutex::ScopedLock __locker(m_ElementAccessMutex); - theOverride->m_TimeCallback->OnTimeFinished(); - theOverride->m_TimeCallback->Release(); - theOverride->m_TimeCallback = NULL; - } - return false; - } else { - Q3DStudio::BOOL theReachedEndTime = m_TimePolicy.ComputeTime(inGlobalTime); - if (theReachedEndTime) - return true; - - return false; - } - } - - // There are four conditions this happens: - // 1. This object is getting destroyed - // 2. A new override is being set. - // 3. The compoent switched slides. - // 4. The component was deactivated. - void RemoveOverride() - { - if (m_TimePolicyOverride) { - if (m_TimePolicyOverride->m_TimeCallback) { - Mutex::ScopedLock __locker(m_ElementAccessMutex); - m_TimePolicyOverride->m_TimeCallback->Release(); - m_TimePolicyOverride->m_TimeCallback = NULL; - } - - NVDelete(m_Allocator, m_TimePolicyOverride); - m_TimePolicyOverride = NULL; - } - } - - void UpdateLocalTime(TTimeUnit inNewTime, TScanBuffer &inScanBuffer, IActivityZone &inZone) - { - if (m_TimeDataNeedsUpdate) { - BuildTimeContext(inScanBuffer, inZone); - } - - TTimeUnit newTime = inNewTime; - if (newTime != m_CurrentTime) { - SComponent &myNode = m_Component; - { - Mutex::ScopedLock __locker(m_ElementAccessMutex); - myNode.SetDirty(); - } - STimeEvent searchEvent(STimeEvent::Start, m_Allocator, m_CurrentTime); - bool forward = newTime > m_CurrentTime; - m_CurrentTime = NVMax((TTimeUnit)0, newTime); - - if (forward) { - TTimeEventList::iterator iter = eastl::lower_bound( - m_TimeEvents.begin(), m_TimeEvents.end(), &searchEvent, STimeEventLessThan()); - - for (TTimeEventList::iterator end = m_TimeEvents.end(); - iter != end && (*iter)->m_Time <= newTime; ++iter) { - // Stop only works if the time is greater. - // start works if the time is equal. - bool isActive = true; - if ((*iter)->m_Type == STimeEvent::Stop) - isActive = newTime <= (*iter)->m_Time; - - UpdateNodeList((*iter)->m_AffectedNodes, isActive); - } - } else { - searchEvent.m_Type = STimeEvent::Stop; - TTimeEventList::reverse_iterator iter = - eastl::lower_bound(m_TimeEvents.rbegin(), m_TimeEvents.rend(), &searchEvent, - STimeEventGreaterThan()); - - for (TTimeEventList::reverse_iterator end = m_TimeEvents.rend(); - iter != end && (*iter)->m_Time >= newTime; ++iter) { - bool isActive = true; - if ((*iter)->m_Type == STimeEvent::Start) - isActive = newTime >= (*iter)->m_Time; - - UpdateNodeList((*iter)->m_AffectedNodes, isActive); - } - } - } - } - - void UpdateNodeElementInformation(SElement &inNode) - { - Q3DStudio::UVariant attValue; - if (inNode.GetAttribute(Q3DStudio::ATTRIBUTE_STARTTIME, attValue)) - inNode.m_ActivationManagerNode.m_StartTime = (QT3DSU32)attValue.m_INT32; - - if (inNode.GetAttribute(Q3DStudio::ATTRIBUTE_ENDTIME, attValue)) - inNode.m_ActivationManagerNode.m_StopTime = (QT3DSU32)attValue.m_INT32; - - inNode.m_ActivationManagerNode.m_Flags.SetTimeActive(false); - // Note that we don't set the script information here. The reason is that this requires the - // script list - // and we don't have access to it. Plus it can't change when a slide changes so it is kind - // of irrelevant. - } - - bool BuildTimeContextElementNode(SElement &inNode, QT3DSU32 inGlobalMin, QT3DSU32 inGlobalMax) - { - // Note that just because a node itself does not participate in the time graph, - // this does not mean that its children do not participate in the time graph. - if (inNode.DoesParticipateInTimeGraph()) { - UpdateNodeElementInformation(inNode); - if (inNode.IsUserActive()) { - inGlobalMin = NVMax(inNode.m_ActivationManagerNode.m_StartTime, inGlobalMin); - inGlobalMax = NVMin(inNode.m_ActivationManagerNode.m_StopTime, inGlobalMax); - if (inGlobalMin < inGlobalMax) { - GetTimeEventForTime(inGlobalMin, STimeEvent::Start) - .m_AffectedNodes.push_back(&inNode); - GetTimeEventForTime(inGlobalMax, STimeEvent::Stop) - .m_AffectedNodes.push_back(&inNode); - } - } - } else { - inNode.m_ActivationManagerNode.m_Flags.SetTimeActive(true); - // Carry global min/max information down so children get setup correctly. - inNode.m_ActivationManagerNode.m_StartTime = inGlobalMin; - inNode.m_ActivationManagerNode.m_StopTime = inGlobalMax; - } - // Is it worth looking at children at all - return inNode.IsUserActive(); - } - - void BuildTimeContext(TScanBuffer &inScanBuffer, IActivityZone &inZone) - { - Mutex::ScopedLock __locker(m_ElementAccessMutex); - QT3DS_ASSERT(m_TimeDataNeedsUpdate); - m_TimeDataNeedsUpdate = false; - SComponent &myNode = m_Component; - SElement *theChild = myNode.m_Child; - if (theChild == NULL) { - return; - } - inScanBuffer.clear(); - for (SElement *theChild = myNode.m_Child; theChild; theChild = theChild->m_Sibling) { - inScanBuffer.push_back(theChild); - } - for (QT3DSU32 idx = 0, end = (QT3DSU32)inScanBuffer.size(); idx < end; ++idx) { - SScanBufferEntry theEntry(inScanBuffer[idx]); - bool careAboutChildren = BuildTimeContextElementNode( - *theEntry.m_Node, theEntry.m_StartTime, theEntry.m_EndTime); - if (careAboutChildren && theEntry.m_Node->IsComponent() == false) { - for (SElement *theChild = theEntry.m_Node->m_Child; theChild; - theChild = theChild->m_Sibling) { - inScanBuffer.push_back(SScanBufferEntry( - theChild, theEntry.m_Node->m_ActivationManagerNode.m_StartTime, - theEntry.m_Node->m_ActivationManagerNode.m_StopTime)); - } - end = (QT3DSU32)inScanBuffer.size(); - } - if (theEntry.m_Node->IsComponent()) - inZone.AddActivityItems(*theEntry.m_Node); - } - } - - void SetElementDirty(SElement &inNode) - { - SElement *theComponentParent = &inNode.GetComponentParent(); - if (inNode.IsComponent() && inNode.m_Parent) - theComponentParent = &inNode.m_Parent->GetComponentParent(); - - QT3DS_ASSERT(theComponentParent == &m_Component); - if (m_AllNodesDirty == false) { - // We check independent items every frame anyway so it isn't worth setting them dirty - // here. - if (inNode.IsIndependent() == false) { - m_DirtyList.insert(inNode); - } - - // Dirty to root time context. This ensures that if we run an activate scan starting at - // a parent - // we won't have to re-run the scan at this node because it will not be dirty. - // This also makes sure that if we mark all nodes dirty we continue the activate scan - // till we hit at least - // this node. - SElement *theParent = inNode.m_Parent; - while (theParent) { - if (theParent->IsComponent() - || theParent->m_ActivationManagerNode.m_Flags.IsChildDirty()) - theParent = NULL; - else { - SActivationManagerNode &theNode = theParent->m_ActivationManagerNode; - theNode.m_Flags.SetChildDirty(); - theParent = theParent->m_Parent; - } - } - } - } - - static void UpdateItemScriptStatus(SElement &inNode, bool activeAndHasScript, - TElementAndSortKeyList &scriptBuffer) - { - QT3DSU32 theIndex = inNode.Depth(); - eastl::pair<element::SElement *, QT3DSU32> theInsertedItem(&inNode, theIndex); - if (activeAndHasScript) { - if (inNode.m_ActivationManagerNode.m_Flags.HasScript() == false) { - scriptBuffer.push_back(theInsertedItem); - inNode.m_ActivationManagerNode.m_Flags.SetHasScript(true); - } - } else { - if (inNode.m_ActivationManagerNode.m_Flags.HasScript() == true) { - TElementAndSortKeyList::iterator theFind = - eastl::find(scriptBuffer.begin(), scriptBuffer.end(), theInsertedItem); - if (theFind != scriptBuffer.end()) - scriptBuffer.erase(theFind); - inNode.m_ActivationManagerNode.m_Flags.SetHasScript(false); - } - } - } - - static void HandleActivationChange(SElement &inNode, TElementAndSortKeyList &activateBuffer, - TElementAndSortKeyList &deactivateBuffer, - TElementAndSortKeyList &scriptBuffer, - Mutex &inElementAccessMutex, bool &scriptBufferRequiresSort, - bool inIsActive) - { - Mutex::ScopedLock __locker(inElementAccessMutex); - TElementAndSortKey theKey(&inNode, inNode.Depth()); - if (inIsActive) { - activateBuffer.push_back(TElementAndSortKey(theKey)); - } else { - deactivateBuffer.push_back(theKey); - } - - if (inNode.Flags().HasScriptCallbacks()) { - UpdateItemScriptStatus(inNode, inIsActive, scriptBuffer); - scriptBufferRequiresSort = true; - } - inNode.SetGlobalActive(inIsActive); - } - - // Runs once we notice that the item's global active status has changed. - // Note we explicitly do not update independent items because those are updated - // as the first step of each time context update itself. - // We do, however, remove them from the dirty list here. - static void RunActivateScan(SElement &inNode, TScanBuffer &inScanBuffer, - TElementAndSortKeyList &activateBuffer, - TElementAndSortKeyList &deactivateBuffer, - TElementAndSortKeyList &scriptBuffer, Mutex &inElementAccessMutex, - bool &scriptBufferRequiresSort, bool inRunFullScan) - { - inScanBuffer.clear(); - - // Block used to hide variables to avoid an error. - { - bool parentActive = true; - SElement *theParent = inNode.m_Parent; - if (theParent != NULL) - parentActive = theParent->IsGlobalActive(); - - inScanBuffer.push_back(SScanBufferEntry(&inNode, parentActive)); - } - - for (QT3DSU32 idx = 0, end = inScanBuffer.size(); idx < end; ++idx) { - SScanBufferEntry theEntry(inScanBuffer[idx]); - SElement *theScanNode = theEntry.m_Node; - QT3DS_ASSERT(theScanNode->IsIndependent() == false); - bool parentActive = theEntry.IsParentActive(); - bool wasActive = theScanNode->IsGlobalActive(); - bool isActive = theScanNode->IsGlobalActive(parentActive); - bool wasChildDirty = theScanNode->m_ActivationManagerNode.m_Flags.IsChildDirty(); - theScanNode->m_ActivationManagerNode.m_Flags.ClearChildDirty(); - bool activateChange = isActive != wasActive; - bool checkChildren = activateChange || (isActive && (wasChildDirty || inRunFullScan)); - if (activateChange) { - HandleActivationChange(*theScanNode, activateBuffer, deactivateBuffer, scriptBuffer, - inElementAccessMutex, scriptBufferRequiresSort, isActive); - } - - if (checkChildren && theScanNode->m_Child) { - for (SElement *theScanNodeChild = theScanNode->m_Child; theScanNodeChild; - theScanNodeChild = theScanNodeChild->m_Sibling) { - if (theScanNodeChild->IsIndependent() == false) - inScanBuffer.push_back(SScanBufferEntry(theScanNodeChild, isActive)); - } - end = inScanBuffer.size(); - } - } - } - - void RunDirtyScan(TScanBuffer &inScanBuffer, TElementNodePtrList &inTempDirtyList, - TElementAndSortKeyList &activateBuffer, - TElementAndSortKeyList &deactivateBuffer, - TElementAndSortKeyList &scriptBuffer, bool &scriptBufferRequiresSort) - { - if (m_AllNodesDirty == true) { - inTempDirtyList.clear(); - SComponent &myNode = m_Component; - for (SElement *theChild = myNode.m_Child; theChild; theChild = theChild->m_Sibling) { - // Independent nodes don't need to be in the dirty list. - if (theChild->IsIndependent() == false) - inTempDirtyList.push_back(theChild); - } - } else { - inTempDirtyList.assign(m_DirtyList.begin(), m_DirtyList.end()); - // Reset nodes that are dirty to *not* be dirty. - m_DirtyList.clear(); - // We have to sort the dirty list because it may have nodes out of order and the active - // algorithm requires parents before children. We use the depth member variable to - // achieve this. - eastl::sort(inTempDirtyList.begin(), inTempDirtyList.end(), SElementPtrSort()); - } - for (QT3DSU32 idx = 0, end = (QT3DSU32)inTempDirtyList.size(); idx < end; ++idx) { - SElement &dirtyNode(*inTempDirtyList[idx]); - // This is slightly inefficient in the case where a both a child and parent are in the - // dirty list. - // This case has got to be extremely rare in practice, however. - RunActivateScan(dirtyNode, inScanBuffer, activateBuffer, deactivateBuffer, scriptBuffer, - m_ElementAccessMutex, scriptBufferRequiresSort, m_AllNodesDirty); - } - // Set at end so while debugging you can see if all nodes were dirty on method entry. - m_AllNodesDirty = false; - } - - bool Update(TTimeUnit inGlobalTime, TScanBuffer &inScanBuffer, - TElementNodePtrList &inTempDirtyList, TElementAndSortKeyList &activateBuffer, - TElementAndSortKeyList &deactivateBuffer, TElementAndSortKeyList &scriptBuffer, - bool &scriptBufferRequiresSort, Q3DStudio::CComponentManager &inComponentManager, - IPerfTimer &inPerfTimer, IActivityZone &inZone) - { - QT3DSU64 start = qt3ds::foundation::Time::getCurrentCounterValue(); - SComponent &theContextNode = m_Component; - bool parentActive = true; - SElement *theParent = theContextNode.m_Parent; - if (theParent != NULL) - parentActive = theParent->IsGlobalActive(); - - bool wasActive = theContextNode.IsGlobalActive(); - bool isActive = theContextNode.IsGlobalActive(parentActive); - bool activationChange = isActive != wasActive; - inPerfTimer.Update("ActivationManager - Update Initial Vars", - qt3ds::foundation::Time::getCurrentCounterValue() - start); - if (activationChange) { - SStackPerfTimer __timer(inPerfTimer, "ActivationManager - Activation Change"); - HandleActivationChange(theContextNode, activateBuffer, deactivateBuffer, scriptBuffer, - m_ElementAccessMutex, scriptBufferRequiresSort, isActive); - m_DirtyList.clear(); - m_AllNodesDirty = true; - if (isActive) { - Mutex::ScopedLock __locker(m_ElementAccessMutex); - inComponentManager.GotoSlideIndex(&theContextNode, 1, false); - } else - RemoveOverride(); - } - if (isActive) { - SStackPerfTimer __timer(inPerfTimer, "ActivationManager - Update Local Time"); - bool atEndOfTime = CalculateNewTime(inGlobalTime); - if (atEndOfTime) { - Mutex::ScopedLock __locker(m_ElementAccessMutex); - if (theContextNode.IsPlayThrough()) - inComponentManager.PlaythroughToSlide(&theContextNode); - } - // Note the slide may have changed here and thus updated our time policy. - // Set time active flags based on time. - UpdateLocalTime(m_TimePolicy.GetTime(), inScanBuffer, inZone); - } - if (isActive || activationChange) { - if (m_AllNodesDirty || m_DirtyList.size()) { - SStackPerfTimer __timer(inPerfTimer, "ActivationManager - Dirty Scan"); - RunDirtyScan(inScanBuffer, inTempDirtyList, activateBuffer, deactivateBuffer, - scriptBuffer, scriptBufferRequiresSort); - } - } - return isActive || activationChange; - } - - void GoToTime(TTimeUnit inTime) - { - if (m_TimePolicyOverride) { - m_TimePolicyOverride->SetTime(m_TimePolicy, inTime); - } else { - m_TimePolicy.SetTime(inTime); - } - } -}; - -IMPLEMENT_INVASIVE_SINGLE_LIST(TimeContext, m_NextSibling); - -struct SActivityZone : public IActivityZone -{ - typedef nvhash_map<SElement *, NVScopedRefCounted<STimeContext>> TComponentTimeContextMap; - NVFoundationBase &m_Foundation; - Q3DStudio::CPresentation &m_Presentation; - IStringTable &m_StringTable; - nvvector<SElement *> m_RootElements; - TComponentTimeContextMap m_TimeContexts; - // These could potentially not be sorted but for 7.5 and TZ3 I don't want to risk the - // bugs assocated with not producing the exact same output as the original algorithm. - TElementAndSortKeyList m_ActivatedItems; - TElementAndSortKeyList m_DeactivatedItems; - - // This will always need to be sorted because it is maintained across update calls - TElementAndSortKeyList m_ScriptItems; - - // Temporaries used while scanning nodes for various features. - TScanBuffer m_ScanBuffer; - TElementNodePtrList m_TempDirtyList; - nvvector<STimeContext *> m_TimeContextScanBuffer; - - TTimeContextList m_RootContexts; - Mutex &m_ElementAccessMutex; - Mutex m_UpdateCheckMutex; - Sync m_UpdateSync; - TTimeUnit m_GlobalTime; - IPerfTimer *m_PerfTimer; - STypeDesc m_DummyTypeDesc; - SComponent m_DummyComponent; - STimeContext m_DummyContext; - bool m_Active; - // True if m_ScriptItems needs to be resorted. - bool m_ScriptRequiresSort; - bool m_Updating; - - QT3DSI32 mRefCount; - - SActivityZone(NVFoundationBase &inFnd, Q3DStudio::CPresentation &inPres, - IStringTable &inStrTable, Mutex &inElementAccessMutex) - : m_Foundation(inFnd) - , m_Presentation(inPres) - , m_StringTable(inStrTable) - , m_RootElements(inFnd.getAllocator(), "Elements") - , m_TimeContexts(inFnd.getAllocator(), "TimeContexts") - , m_ActivatedItems(inFnd.getAllocator(), "m_ActivatedItems") - , m_DeactivatedItems(inFnd.getAllocator(), "m_DeactivatedItems") - , m_ScriptItems(inFnd.getAllocator(), "m_ScriptItems") - , m_ScanBuffer(inFnd.getAllocator(), "m_ScanBuffer") - , m_TempDirtyList(inFnd.getAllocator(), "m_TempDirtyList") - , m_TimeContextScanBuffer(inFnd.getAllocator(), "m_TimeContextScanBuffer") - , m_ElementAccessMutex(inElementAccessMutex) - , m_UpdateCheckMutex(inFnd.getAllocator()) - , m_UpdateSync(inFnd.getAllocator()) - , m_GlobalTime(0) - , m_PerfTimer(NULL) - , m_DummyComponent(m_DummyTypeDesc) - , m_DummyContext(m_Foundation.getAllocator(), m_DummyComponent, m_ElementAccessMutex) - , m_Active(true) - , m_ScriptRequiresSort(true) - , m_Updating(false) - , mRefCount(0) - { - } - - QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation.getAllocator()) - - Q3DStudio::CPresentation &GetPresentation() override { return m_Presentation; } - - static void SortElementBuffer(nvvector<eastl::pair<element::SElement *, QT3DSU32>> &inBuffer) - { - eastl::sort(inBuffer.begin(), inBuffer.end(), SElementIndexPairSorter()); - } - - static void AddElementNodeToBuffer(nvvector<eastl::pair<element::SElement *, QT3DSU32>> &inBuffer, - SElement &inNode) - { - eastl::pair<element::SElement *, QT3DSU32> insertItem(&inNode, inNode.Depth()); - QT3DS_ASSERT(eastl::find(inBuffer.begin(), inBuffer.end(), insertItem) == inBuffer.end()); - inBuffer.push_back(insertItem); - } - - TActivityItemBuffer GetActivatedItems() override { return m_ActivatedItems; } - - TActivityItemBuffer GetDeactivatedItems() override { return m_DeactivatedItems; } - // All active items that are script enabled. - TActivityItemBuffer GetScriptItems() override - { - // Created in a delayed way. - if (m_ScriptRequiresSort) { - m_ScriptRequiresSort = false; - SortElementBuffer(m_ScriptItems); - } - return m_ScriptItems; - } - - void SetZoneActive(bool inActive) override { m_Active = inActive; } - bool IsZoneActive() override { return m_Active; } - - SActivationManagerNode *GetElementNodeForElement(TActivityItem item) - { - return &item.m_ActivationManagerNode; - } - - STimeContext &GetItemTimeContext(SElement &inNode) - { - SElement &theComponent = inNode.GetComponentParent(); - if (!theComponent.IsComponent()) { - QT3DS_ASSERT(false); - return m_DummyContext; - } - - eastl::pair<TComponentTimeContextMap::iterator, bool> inserter = m_TimeContexts.insert( - eastl::make_pair(&theComponent, NVScopedRefCounted<STimeContext>())); - if (inserter.second) { - inserter.first->second = QT3DS_NEW(m_Foundation.getAllocator(), STimeContext)( - m_Foundation.getAllocator(), static_cast<SComponent &>(theComponent), - m_ElementAccessMutex); - STimeContext &theNewContext = *inserter.first->second; - if (theComponent.m_Parent == NULL) - m_RootContexts.push_back(theNewContext); - else { - STimeContext &parentContext = GetItemTimeContext(*theComponent.m_Parent); - parentContext.m_Children.push_back(theNewContext); - } - } - return *inserter.first->second.mPtr; - } - - void AddActivityItems(TActivityItem inNode) override - { - if (inNode.m_Parent == NULL) - m_RootElements.push_back(&inNode); - - GetItemTimeContext(inNode); - } - - CTimePolicy *GetOwnedTimePolicy(TActivityItem item) override - { - return &GetItemTimeContext(item).m_TimePolicy; - } - - virtual SComponentTimePolicyOverride * - GetOrCreateItemComponentOverride(TActivityItem item, float inMultiplier, TTimeUnit inEndTime, - IComponentTimeOverrideFinishedCallback *inCallback) override - { - STimeContext &theContext = GetItemTimeContext(item); - - theContext.RemoveOverride(); - theContext.m_TimePolicyOverride = - QT3DS_NEW(m_Foundation.getAllocator(), - SComponentTimePolicyOverride)(&item, inMultiplier, inEndTime, inCallback); - theContext.m_TimePolicy.SetPaused(false); - - return theContext.m_TimePolicyOverride; - } - - // If I am independent, then I am my own time parent. - // else travel up the chain till you find an indpendent node. - SElement &GetItemTimeParentNode(SElement &inNode) - { - if (inNode.m_Parent != NULL) { - SElement &theParent = *inNode.m_Parent; - if (theParent.IsIndependent()) - return theParent; - return GetItemTimeParentNode(theParent); - } - // All roots are time independent by definition. - return inNode; - } - - TActivityItemPtr GetItemTimeParent(SElement &inNode) override - { - return &GetItemTimeParentNode(inNode); - } - - void InsertIntoAppropriateDirtyList(SElement &inNode) - { - // This may need to be faster at some point... - GetItemTimeContext(inNode).SetElementDirty(inNode); - } - - bool GetItemUserActive(TActivityItem item) override { return item.IsExplicitActive(); } - - void UpdateItemScriptStatus(TActivityItem item) override - { - if (item.IsGlobalActive()) { - STimeContext::UpdateItemScriptStatus(item, item.Flags().HasScriptCallbacks(), - m_ScriptItems); - m_ScriptRequiresSort = true; - } - } - - void UpdateItemInfo(TActivityItem item) override { GetItemTimeContext(item).Reset(); } - - // Order of events will be: - // 1. On Slide Change - // 2. Time Update - // 3. On Slide Change - // 4. Update Local Time - void OnSlideChange(TActivityItem item) override - { - STimeContext &theContext = GetItemTimeContext(item); - // Rebuilding the context sets all the elements dirty. - // This takes care of everything *but* the script item changes. - theContext.Reset(); - theContext.RemoveOverride(); - } - - bool GetItemTimeActive(TActivityItem item) override - { - SActivationManagerNode *theNode = GetElementNodeForElement(item); - if (theNode) - return theNode->m_Flags.IsTimeActive(); - return false; - } - - TTimeUnit GetItemLocalTime(TActivityItem item) override - { - SElement *theElem = &item.GetComponentParent(); - if (item.IsComponent() && item.m_Parent) - theElem = &item.m_Parent->GetComponentParent(); - - return GetItemTimeContext(*theElem).m_CurrentTime; - } - - TTimeUnit GetItemComponentTime(TActivityItem item) override - { - return GetItemTimeContext(item).m_CurrentTime; - } - - bool IsUpdating() override - { - Mutex::ScopedLock __locker(m_UpdateCheckMutex); - return m_Updating; - } - - void EndUpdate() override - { - m_UpdateSync.reset(); - while (IsUpdating()) - m_UpdateSync.wait(); - } - - void DoUpdate() - { - SStackPerfTimer __timer(m_PerfTimer, "ActivationManager - DoUpdate"); - if (m_Active) { - // We know that parent elements are added before children. - // So we know the time contexts are in an appropriate order, assuming they completely - // resolve their results before the next time context runs. - Q3DStudio::CComponentManager &theManager = - static_cast<Q3DStudio::CComponentManager &>(m_Presentation.GetComponentManager()); - m_TimeContextScanBuffer.clear(); - - for (TTimeContextList::iterator iter = m_RootContexts.begin(), - end = m_RootContexts.end(); - iter != end; ++iter) - m_TimeContextScanBuffer.push_back(&(*iter)); - - for (QT3DSU32 idx = 0, end = m_TimeContextScanBuffer.size(); idx < end; ++idx) { - STimeContext &theContext = *m_TimeContextScanBuffer[idx]; - bool checkChildren = - theContext.Update(m_GlobalTime, m_ScanBuffer, m_TempDirtyList, m_ActivatedItems, - m_DeactivatedItems, m_ScriptItems, m_ScriptRequiresSort, - theManager, *m_PerfTimer, *this); - if (checkChildren) { - for (TTimeContextList::iterator timeIter = theContext.m_Children.begin(), - timeEnd = theContext.m_Children.end(); - timeIter != timeEnd; ++timeIter) { - m_TimeContextScanBuffer.push_back(&(*timeIter)); - } - end = m_TimeContextScanBuffer.size(); - } - } - } - - eastl::sort(m_ActivatedItems.begin(), m_ActivatedItems.end(), SElementIndexPairSorter()); - eastl::sort(m_DeactivatedItems.begin(), m_DeactivatedItems.end(), - SElementIndexPairSorter()); - Mutex::ScopedLock __locker(m_UpdateCheckMutex); - { - m_Updating = false; - m_UpdateSync.set(); - } - } - - static void UpdateCallback(void *data) - { - SActivityZone *theZone = reinterpret_cast<SActivityZone *>(data); - theZone->DoUpdate(); - } - - void BeginUpdate(TTimeUnit inGlobalTime, IPerfTimer &inPerfTimer, - IThreadPool &inThreadPool) override - { - // It is expected that an update is not running. - m_ActivatedItems.clear(); - m_DeactivatedItems.clear(); - m_GlobalTime = inGlobalTime; - m_PerfTimer = &inPerfTimer; - m_Updating = true; - inThreadPool.AddTask(this, UpdateCallback, NULL); - } - - void GoToTime(TActivityItem inItem, TTimeUnit inTime) override - { - GetItemTimeContext(inItem).GoToTime(inTime); - } -}; - -struct SActivityZoneManager : public IActivityZoneManager -{ - NVFoundationBase &m_Foundation; - IStringTable &m_StringTable; - // Zones may access the element mutex on destruction *so* it is important that - // it is destroyed *after* the zone list. - Mutex m_ElementAccessMutex; - nvvector<NVScopedRefCounted<SActivityZone>> m_Zones; - QT3DSI32 mRefCount; - - SActivityZoneManager(NVFoundationBase &fnd, IStringTable &inStrTable) - : m_Foundation(fnd) - , m_StringTable(inStrTable) - , m_ElementAccessMutex(m_Foundation.getAllocator()) - , m_Zones(m_Foundation.getAllocator(), "m_Zones") - , mRefCount(0) - { - } - - QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation.getAllocator()) - - IActivityZone &CreateActivityZone(Q3DStudio::CPresentation &inPresentation) override - { - m_Zones.push_back(QT3DS_NEW(m_Foundation.getAllocator(), SActivityZone)( - m_Foundation, inPresentation, m_StringTable, m_ElementAccessMutex)); - return *m_Zones.back().mPtr; - } -}; -} - -IActivityZoneManager & -IActivityZoneManager::CreateActivityZoneManager(NVFoundationBase &inFoundation, - IStringTable &inStrTable) -{ - return *QT3DS_NEW(inFoundation.getAllocator(), SActivityZoneManager)(inFoundation, inStrTable); -} |