History

abstract DiffTraversal out of EntityTreeSendThread

Andrew Meadows committed 9 years ago

Commit 0758b601 parent 5fba4cb6 files · +366 −276Browse files

Showing the changes to assignment-client/src/entities/EntityTreeSendThread.cpp (1 of 6 files). Show all

Unified · Split

assignment-client/src/entities/EntityTreeSendThread.cpp+42−131
@@ -10,19 +10,12 @@ · 9 unmodified lines
10//10//
11 11
12#include "EntityTreeSendThread.h"12#include "EntityTreeSendThread.h"
13#include <iostream> // adebug
14 13
15#include <EntityNodeData.h>14#include <EntityNodeData.h>
16#include <EntityTypes.h>15#include <EntityTypes.h>
17 16
18#include "EntityServer.h"17#include "EntityServer.h"
19 18
20EntityTreeSendThread::EntityTreeSendThread(OctreeServer* myServer, const SharedNodePointer& node)
21 : OctreeSendThread(myServer, node) {
22 const int32_t MIN_PATH_DEPTH = 16;
23 _traversalPath.reserve(MIN_PATH_DEPTH);
24}
25
26void EntityTreeSendThread::preDistributionProcessing() {19void EntityTreeSendThread::preDistributionProcessing() {
27 auto node = _node.toStrongRef();20 auto node = _node.toStrongRef();
28 auto nodeData = static_cast<EntityNodeData*>(node->getLinkedData());21 auto nodeData = static_cast<EntityNodeData*>(node->getLinkedData());
@@ -90,14 +83,14 @@ void EntityTreeSendThread::preDistributionProcessing() { · 61 unmodified lines
90void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,83void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, OctreeQueryNode* nodeData,
91 bool viewFrustumChanged, bool isFullScene) {84 bool viewFrustumChanged, bool isFullScene) {
92 // BEGIN EXPERIMENTAL DIFFERENTIAL TRAVERSAL85 // BEGIN EXPERIMENTAL DIFFERENTIAL TRAVERSAL
93 {
94 // DEBUG HACK: trigger traversal (Again) every so often
95 const uint64_t TRAVERSE_AGAIN_PERIOD = 2 * USECS_PER_SECOND;
96 if (!viewFrustumChanged && usecTimestampNow() > _startOfCompletedTraversal + TRAVERSE_AGAIN_PERIOD) {
97 viewFrustumChanged = true;
98 }
99 }
100 if (nodeData->getUsesFrustum()) {86 if (nodeData->getUsesFrustum()) {
87 {
88 // DEBUG HACK: trigger traversal (Again) every so often
89 const uint64_t TRAVERSE_AGAIN_PERIOD = 4 * USECS_PER_SECOND;
90 if (!viewFrustumChanged && usecTimestampNow() > _traversal.getStartOfCompletedTraversal() + TRAVERSE_AGAIN_PERIOD) {
91 viewFrustumChanged = true;
92 }
93 }
101 if (viewFrustumChanged) {94 if (viewFrustumChanged) {
102 ViewFrustum viewFrustum;95 ViewFrustum viewFrustum;
103 nodeData->copyCurrentViewFrustum(viewFrustum);96 nodeData->copyCurrentViewFrustum(viewFrustum);
@@ -105,28 +98,14 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O · 1 unmodified line
105 startNewTraversal(viewFrustum, root);98 startNewTraversal(viewFrustum, root);
106 }99 }
107 }100 }
108 if (!_traversalPath.empty()) {101 if (!_traversal.finished()) {
109 uint64_t startTime = usecTimestampNow();102 uint64_t startTime = usecTimestampNow();
110 uint64_t now = startTime;
111 103
112 VisibleElement next;104 const uint64_t TIME_BUDGET = 100000; // usec
113 getNextVisibleElement(next);105 _traversal.traverse(TIME_BUDGET);
114 while (next.element) {
115 if (next.element->hasContent()) {
116 _scanNextElementCallback(next);
117 }
118 106
119 // TODO: pick a reasonable budget for each partial traversal107 uint64_t dt = usecTimestampNow() - startTime;
120 const uint64_t PARTIAL_TRAVERSAL_TIME_BUDGET = 100000; // usec108 std::cout << "adebug traversal complete " << " Q.size = " << _sendQueue.size() << " dt = " << dt << std::endl; // adebug
121 now = usecTimestampNow();
122 if (now - startTime > PARTIAL_TRAVERSAL_TIME_BUDGET) {
123 break;
124 }
125 getNextVisibleElement(next);
126 }
127
128 uint64_t dt = now - startTime;
129 std::cout << "adebug traversal complete " << " Q.size = " << _sendQueue.size() << " dt = " << dt << std::endl; // adebug
130 }109 }
131 if (!_sendQueue.empty()) {110 if (!_sendQueue.empty()) {
132 // print what needs to be sent111 // print what needs to be sent
@@ -134,11 +113,9 @@ void EntityTreeSendThread::traverseTreeAndSendContents(SharedNodePointer node, O · 1 unmodified line
134 PrioritizedEntity entry = _sendQueue.top();113 PrioritizedEntity entry = _sendQueue.top();
135 EntityItemPointer entity = entry.getEntity();114 EntityItemPointer entity = entry.getEntity();
136 if (entity) {115 if (entity) {
137 std::cout << "adebug '" << entity->getName().toStdString() << "'"116 std::cout << "adebug send '" << entity->getName().toStdString() << "'" << " : " << entry.getPriority() << std::endl; // adebug
138 << " : " << entry.getPriority() << std::endl; // adebug
139 }117 }
140 _sendQueue.pop();118 _sendQueue.pop();
141 std::cout << "adebug" << std::endl; // adebug
142 }119 }
143 }120 }
144 // END EXPERIMENTAL DIFFERENTIAL TRAVERSAL121 // END EXPERIMENTAL DIFFERENTIAL TRAVERSAL
@@ -195,39 +172,29 @@ bool EntityTreeSendThread::addDescendantsToExtraFlaggedEntities(const QUuid& fil · 50 unmodified lines
195 return hasNewChild || hasNewDescendants;172 return hasNewChild || hasNewDescendants;
196}173}
197 174
198void EntityTreeSendThread::startNewTraversal(const ViewFrustum& viewFrustum, EntityTreeElementPointer root) {175void EntityTreeSendThread::startNewTraversal(const ViewFrustum& view, EntityTreeElementPointer root) {
176 DiffTraversal::Type type = _traversal.prepareNewTraversal(view, root);
199 // there are three types of traversal:177 // there are three types of traversal:
200 //178 //
201 // (1) FirstTime = at login --> find everything in view179 // (1) FirstTime = at login --> find everything in view
202 // (2) Again = view hasn't changed --> find what has changed since last complete traversal180 // (2) Repeat = view hasn't changed --> find what has changed since last complete traversal
203 // (3) Differential = view has changed --> find what has changed or in new view but not old181 // (3) Differential = view has changed --> find what has changed or in new view but not old
204 //182 //
205 // For each traversal type we define two callback lambdas:183 // The "scanCallback" we provide to the traversal depends on the type:
206 //
207 // _getNextVisibleElementCallback = identifies elements that need to be traversed,i
208 // updates VisibleElement ref argument with pointer-to-element and view-intersection
209 // (INSIDE, INTERSECT, or OUTSIDE)
210 //
211 // _scanNextElementCallback = identifies entities that need to be appended to _sendQueue
212 //184 //
213 // The _conicalView is updated here as a cached view approximation used by the lambdas for efficient185 // The _conicalView is updated here as a cached view approximation used by the lambdas for efficient
214 // computation of entity sorting priorities.186 // computation of entity sorting priorities.
215 //187 //
216 if (_startOfCompletedTraversal == 0) {188 _conicalView.set(_traversal.getCurrentView());
217 // first time
218 _currentView = viewFrustum;
219 _conicalView.set(_currentView);
220
221 _getNextVisibleElementCallback = [&](VisibleElement& next) {
222 _traversalPath.back().getNextVisibleElementFirstTime(next, _currentView);
223 };
224 189
225 _scanNextElementCallback = [&](VisibleElement& next) {190 switch (type) {
191 case DiffTraversal::First:
192 _traversal.setScanCallback([&] (DiffTraversal::VisibleElement& next) {
226 next.element->forEachEntity([&](EntityItemPointer entity) {193 next.element->forEachEntity([&](EntityItemPointer entity) {
227 bool success = false;194 bool success = false;
228 AACube cube = entity->getQueryAACube(success);195 AACube cube = entity->getQueryAACube(success);
229 if (success) {196 if (success) {
230 if (_currentView.cubeIntersectsKeyhole(cube)) {197 if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
231 float priority = _conicalView.computePriority(cube);198 float priority = _conicalView.computePriority(cube);
232 _sendQueue.push(PrioritizedEntity(entity, priority));199 _sendQueue.push(PrioritizedEntity(entity, priority));
233 }200 }
@@ -236,21 +203,18 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& viewFrustum, Ent · 2 unmodified lines
236 _sendQueue.push(PrioritizedEntity(entity, WHEN_IN_DOUBT_PRIORITY));203 _sendQueue.push(PrioritizedEntity(entity, WHEN_IN_DOUBT_PRIORITY));
237 }204 }
238 });205 });
239 };206 });
240 } else if (_currentView.isVerySimilar(viewFrustum)) {207 break;
241 // again208 case DiffTraversal::Repeat:
242 _getNextVisibleElementCallback = [&](VisibleElement& next) {209 _traversal.setScanCallback([&] (DiffTraversal::VisibleElement& next) {
243 _traversalPath.back().getNextVisibleElementAgain(next, _currentView, _startOfCompletedTraversal);210 if (next.element->getLastChangedContent() > _traversal.getStartOfCompletedTraversal()) {
244 };211 uint64_t timestamp = _traversal.getStartOfCompletedTraversal();
245
246 _scanNextElementCallback = [&](VisibleElement& next) {
247 if (next.element->getLastChangedContent() > _startOfCompletedTraversal) {
248 next.element->forEachEntity([&](EntityItemPointer entity) {212 next.element->forEachEntity([&](EntityItemPointer entity) {
249 if (entity->getLastEdited() > _startOfCompletedTraversal) {213 if (entity->getLastEdited() > timestamp) {
250 bool success = false;214 bool success = false;
251 AACube cube = entity->getQueryAACube(success);215 AACube cube = entity->getQueryAACube(success);
252 if (success) {216 if (success) {
253 if (next.intersection == ViewFrustum::INSIDE || _currentView.cubeIntersectsKeyhole(cube)) {217 if (next.intersection == ViewFrustum::INSIDE || _traversal.getCurrentView().cubeIntersectsKeyhole(cube)) {
254 float priority = _conicalView.computePriority(cube);218 float priority = _conicalView.computePriority(cube);
255 _sendQueue.push(PrioritizedEntity(entity, priority));219 _sendQueue.push(PrioritizedEntity(entity, priority));
256 }220 }
@@ -261,26 +225,20 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& viewFrustum, Ent · 4 unmodified lines
261 }225 }
262 });226 });
263 }227 }
264 };228 });
265 } else {229 break;
266 // differential230 case DiffTraversal::Differential:
267 _currentView = viewFrustum;231 _traversal.setScanCallback([&] (DiffTraversal::VisibleElement& next) {
268 _conicalView.set(_currentView);232 // NOTE: for Differential case: next.intersection is against completedView not currentView
269 233 uint64_t timestamp = _traversal.getStartOfCompletedTraversal();
270 _getNextVisibleElementCallback = [&](VisibleElement& next) {234 if (next.element->getLastChangedContent() > timestamp || next.intersection != ViewFrustum::INSIDE) {
271 _traversalPath.back().getNextVisibleElementDifferential(next, _currentView, _completedView, _startOfCompletedTraversal);
272 };
273
274 _scanNextElementCallback = [&](VisibleElement& next) {
275 // NOTE: for differential case next.intersection is against _completedView not _currentView
276 if (next.element->getLastChangedContent() > _startOfCompletedTraversal || next.intersection != ViewFrustum::INSIDE) {
277 next.element->forEachEntity([&](EntityItemPointer entity) {235 next.element->forEachEntity([&](EntityItemPointer entity) {
278 bool success = false;236 bool success = false;
279 AACube cube = entity->getQueryAACube(success);237 AACube cube = entity->getQueryAACube(success);
280 if (success) {238 if (success) {
281 if (_currentView.cubeIntersectsKeyhole(cube) &&239 if (_traversal.getCurrentView().cubeIntersectsKeyhole(cube) &&
282 (entity->getLastEdited() > _startOfCompletedTraversal ||240 (entity->getLastEdited() > timestamp ||
283 !_completedView.cubeIntersectsKeyhole(cube))) {241 !_traversal.getCompletedView().cubeIntersectsKeyhole(cube))) {
284 float priority = _conicalView.computePriority(cube);242 float priority = _conicalView.computePriority(cube);
285 _sendQueue.push(PrioritizedEntity(entity, priority));243 _sendQueue.push(PrioritizedEntity(entity, priority));
286 }244 }
@@ -290,55 +248,8 @@ void EntityTreeSendThread::startNewTraversal(const ViewFrustum& viewFrustum, Ent · 3 unmodified lines
290 }248 }
291 });249 });
292 }250 }
293 };251 });
294 }252 break;
295
296 _traversalPath.clear();
297 assert(root);
298 _traversalPath.push_back(TraversalWaypoint(root));
299 // set root fork's index such that root element returned at getNextElement()
300 _traversalPath.back().initRootNextIndex();
301
302 _startOfCurrentTraversal = usecTimestampNow();
303}
304
305void EntityTreeSendThread::getNextVisibleElement(VisibleElement& next) {
306 if (_traversalPath.empty()) {
307 next.element.reset();
308 next.intersection = ViewFrustum::OUTSIDE;
309 return;
310 }
311 _getNextVisibleElementCallback(next);
312 if (next.element) {
313 int8_t nextIndex = _traversalPath.back().getNextIndex();
314 if (nextIndex > 0) {
315 // next.element needs to be added to the path
316 _traversalPath.push_back(TraversalWaypoint(next.element));
317 }
318 } else {
319 // we're done at this level
320 while (!next.element) {
321 // pop one level
322 _traversalPath.pop_back();
323 if (_traversalPath.empty()) {
324 // we've traversed the entire tree
325 _completedView = _currentView;
326 _startOfCompletedTraversal = _startOfCurrentTraversal;
327 return;
328 }
329 // keep looking for next
330 _getNextVisibleElementCallback(next);
331 if (next.element) {
332 // we've descended one level so add it to the path
333 _traversalPath.push_back(TraversalWaypoint(next.element));
334 }
335 }
336 }253 }
337}254}
338 255
339// DEBUG method: delete later
340void EntityTreeSendThread::dump() const {
341 for (size_t i = 0; i < _traversalPath.size(); ++i) {
342 std::cout << (int32_t)(_traversalPath[i].getNextIndex()) << "-->";
343 }
344}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t