From 08e21b374824769647fef263b11c99ae45bbad12 Mon Sep 17 00:00:00 2001 From: Brian L <130494071+csciguy8@users.noreply.github.com> Date: Mon, 6 Nov 2023 13:24:18 -0700 Subject: [PATCH] Dispatch TileLoadWork properly --- .../include/Cesium3DTilesSelection/Tileset.h | 18 +- Cesium3DTilesSelection/src/Tileset.cpp | 182 +++++++++++------- 2 files changed, 119 insertions(+), 81 deletions(-) diff --git a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/Tileset.h b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/Tileset.h index 175eacc13..63bfc968c 100644 --- a/Cesium3DTilesSelection/include/Cesium3DTilesSelection/Tileset.h +++ b/Cesium3DTilesSelection/include/Cesium3DTilesSelection/Tileset.h @@ -77,15 +77,14 @@ class RequestDispatcher _pAssetAccessor(pAssetAccessor) {} ~RequestDispatcher() noexcept {} - void SetRequestHeaders( - std::vector& requestHeaders) { - _requestHeaders = requestHeaders; - } - - void QueueLoadWork(std::vector& work); + void QueueRequestWork( + std::vector& work, + std::vector& requestHeaders); void WakeIfNeeded(); + void TakeCompletedWork(size_t maxCount, std::vector& out); + private: void dispatchRequest(TileLoadWork& request); bool stageRequestWork( @@ -570,11 +569,14 @@ class CESIUM3DTILESSELECTION_API Tileset final { double priority); void discoverLoadWork( - std::vector requests, - std::vector& out); + std::vector& requests, + std::vector& outRequests, + std::vector& outProcessing); void addLoadWorkToRequestDispatcher(std::vector& newLoadWork); + void dispatchProcessingWork(std::vector& workVector); + static TraversalDetails createTraversalDetailsForSingleTile( const FrameState& frameState, const Tile& tile, diff --git a/Cesium3DTilesSelection/src/Tileset.cpp b/Cesium3DTilesSelection/src/Tileset.cpp index 718f2e2c2..6b6dcef3b 100644 --- a/Cesium3DTilesSelection/src/Tileset.cpp +++ b/Cesium3DTilesSelection/src/Tileset.cpp @@ -1418,73 +1418,72 @@ Tileset::TraversalDetails Tileset::_visitVisibleChildrenNearToFar( void Tileset::_processWorkerThreadLoadQueue() { CESIUM_TRACE("Tileset::_processWorkerThreadLoadQueue"); -#if 1 // New path // TODO - // -) Take out old maximumSimultaneousTileLoads throttling - // -) Remove setState(TileLoadState::ContentLoading) loading everywhere else // -) Check on Unreal asset accessor (or leave it and make sure there is no // network activity - // -) Dispatch normal doTileContentWork based on dispatcher output // -) Modify doTileContentWork to not do CachingAccessor, or leave it // -) go over TODOS // -) Use worker thread not thread pool? - int32_t maxTileLoads = - static_cast(this->_options.maximumSimultaneousTileLoads); - - // TODO, do we need to move this now? - if (_pTilesetContentManager->getNumberOfTilesLoading() >= maxTileLoads) - return; - - std::vector newLoadWork; - discoverLoadWork(this->_workerThreadLoadQueue, newLoadWork); + std::vector newRequestWork; + std::vector newProcessingWork; + discoverLoadWork( + this->_workerThreadLoadQueue, + newRequestWork, + newProcessingWork); // Add all content requests to Request queue - addLoadWorkToRequestDispatcher(newLoadWork); - - _pRequestDispatcher->SetRequestHeaders( - this->_pTilesetContentManager->getRequestHeaders()); + addLoadWorkToRequestDispatcher(newRequestWork); // Wake up the network request dispatcher _pRequestDispatcher->WakeIfNeeded(); - // Work broken down into load units. Either Tile content work or Raster work. - // TODO issue Tile url request work here and remove from doTileContentWork + // + // We have two input streams of processing work + // - Work that came in from update view this frame + // - Work that had a response that just completed + // + // Give preference to responses that just came in, these are older + // + std::vector workToDispatch; - std::sort(newLoadWork.begin(), newLoadWork.end()); - - for (TileLoadWork& work : newLoadWork) { + int32_t numberOfTilesLoading = + this->_pTilesetContentManager->getNumberOfTilesLoading(); + int32_t maximumSimultaneousTileLoads = + static_cast(this->_options.maximumSimultaneousTileLoads); - if (std::holds_alternative(work.workRef)) { - Tile* pTile = std::get(work.workRef); - assert(pTile); + // TODO, how to figure in raster tiles, getNumberOfThrottledTilesLoading? + // Currently raster tile work dispatches, but doesn't take a slot + int32_t availableSlots = maximumSimultaneousTileLoads - numberOfTilesLoading; + assert(availableSlots >= 0); + if (availableSlots == 0) + return; - if (_pTilesetContentManager->getNumberOfTilesLoading() >= maxTileLoads) - continue; - this->_pTilesetContentManager->doTileContentWork( - *pTile, - work.projections, - _options); - } else { - RasterMappedTo3DTile* pRasterTile = - std::get(work.workRef); - assert(pRasterTile); + // Add completed request work + _pRequestDispatcher->TakeCompletedWork(availableSlots, workToDispatch); + availableSlots -= (int32_t)workToDispatch.size(); + assert(availableSlots >= 0); + + // Add processing work + if (availableSlots > 0) { + std::sort(newProcessingWork.begin(), newProcessingWork.end()); + int countToAdd = + std::min((int32_t)newProcessingWork.size(), availableSlots); + workToDispatch.insert( + workToDispatch.end(), + newProcessingWork.begin(), + newProcessingWork.begin() + countToAdd); + } - RasterOverlayTile* pLoading = pRasterTile->getLoadingTile(); - if (!pLoading) - continue; + // Dispatch it + dispatchProcessingWork(workToDispatch); + /* + THIS CODE NEEDS TO BE PUT BACK RasterOverlayTileProvider& provider = pLoading->getTileProvider(); if (provider.getNumberOfThrottledTilesLoading() >= maxTileLoads) continue; - pRasterTile->loadThrottled(); - } - } - - /* - THIS CODE NEEDS TO BE PUT BACK - // Finalize the parent if necessary, otherwise it may never reach the // Done state. Also double check that we have render content in ensure // we don't assert / crash in finishLoading. The latter will only ever @@ -1495,28 +1494,8 @@ void Tileset::_processWorkerThreadLoadQueue() { finishLoading(*pParentTile, tilesetOptions); } */ - -#else - int32_t maximumSimultaneousTileLoads = - static_cast(this->_options.maximumSimultaneousTileLoads); - - if (this->_pTilesetContentManager->getNumberOfTilesLoading() >= - maximumSimultaneousTileLoads) { - return; - } - - std::vector& queue = this->_workerThreadLoadQueue; - std::sort(queue.begin(), queue.end()); - - for (TileLoadTask& task : queue) { - this->_pTilesetContentManager->loadTileContent(*task.pTile, _options); - if (this->_pTilesetContentManager->getNumberOfTilesLoading() >= - maximumSimultaneousTileLoads) { - break; - } - } -#endif } + void Tileset::_processMainThreadLoadQueue() { CESIUM_TRACE("Tileset::_processMainThreadLoadQueue"); // Process deferred main-thread load tasks with a time budget. @@ -1645,8 +1624,9 @@ Tileset::TraversalDetails Tileset::createTraversalDetailsForSingleTile( } void Tileset::discoverLoadWork( - std::vector requests, - std::vector& out) { + std::vector& requests, + std::vector& outRequests, + std::vector& outProcessing) { for (TileLoadRequest& loadRequest : requests) { std::vector parsedTileWork; this->_pTilesetContentManager->parseTileWork( @@ -1669,7 +1649,11 @@ void Tileset::discoverLoadWork( work.projections, loadRequest.group, 0}; - out.push_back(newWorkUnit); + + if (work.requestUrl.empty()) + outProcessing.push_back(newWorkUnit); + else + outRequests.push_back(newWorkUnit); } // Add the last task at same as input priority @@ -1683,7 +1667,10 @@ void Tileset::discoverLoadWork( loadRequest.group, loadRequest.priority}; - out.push_back(newWorkUnit); + if (lastWork.requestUrl.empty()) + outProcessing.push_back(newWorkUnit); + else + outRequests.push_back(newWorkUnit); } } @@ -1702,19 +1689,48 @@ void Tileset::addLoadWorkToRequestDispatcher( assert(pTile); // Mark this tile as loading now so it doesn't get queued next frame - // TODO, what about raster tiles? pTile->setState(TileLoadState::ContentLoading); workToAdd.push_back(work); } - _pRequestDispatcher->QueueLoadWork(workToAdd); + _pRequestDispatcher->QueueRequestWork( + workToAdd, + this->_pTilesetContentManager->getRequestHeaders()); +} + +void Tileset::dispatchProcessingWork(std::vector& workVector) { + for (TileLoadWork& work : workVector) { + if (std::holds_alternative(work.workRef)) { + Tile* pTile = std::get(work.workRef); + assert(pTile); + + this->_pTilesetContentManager->doTileContentWork( + *pTile, + work.projections, + _options); + } else { + RasterMappedTo3DTile* pRasterTile = + std::get(work.workRef); + assert(pRasterTile); + + RasterOverlayTile* pLoading = pRasterTile->getLoadingTile(); + if (!pLoading) + continue; + + pRasterTile->loadThrottled(); + } + } } -void RequestDispatcher::QueueLoadWork(std::vector& work) { +void RequestDispatcher::QueueRequestWork( + std::vector& work, + std::vector& requestHeaders) { // TODO, assert tile is not already loading? or already post-processing? std::lock_guard lock(_requestsLock); _queuedRequests.insert(_queuedRequests.end(), work.begin(), work.end()); + + _requestHeaders = requestHeaders; } void RequestDispatcher::dispatchRequest(TileLoadWork& request) { @@ -1792,6 +1808,26 @@ bool RequestDispatcher::stageRequestWork( return _queuedRequests.empty(); } +void RequestDispatcher::TakeCompletedWork( + size_t maxCount, + std::vector& out) { + std::lock_guard lock(_requestsLock); + size_t count = _doneRequests.size(); + if (count == 0) + return; + + // Populate our output + size_t numberToTake = std::min(count, maxCount); + out = std::vector( + _doneRequests.begin(), + _doneRequests.begin() + numberToTake); + + // Remove these entries from the source + _doneRequests = std::vector( + _doneRequests.begin() + numberToTake, + _doneRequests.end()); +} + void RequestDispatcher::WakeIfNeeded() { { std::lock_guard lock(_requestsLock);