From 45f4283f4c6ca5b9daf9b19520f58e8f1035cb28 Mon Sep 17 00:00:00 2001 From: Glenn Waldron Date: Tue, 6 Feb 2024 13:16:16 -0500 Subject: [PATCH] Engine: combine the createChild jobs into one job per 4 tile children instead of 4 jobs (one for each) --- src/osgEarth/TerrainOptions | 10 ++ src/osgEarth/TerrainOptions.cpp | 8 ++ src/osgEarthDrivers/engine_rex/TileNode | 40 +++--- src/osgEarthDrivers/engine_rex/TileNode.cpp | 142 ++++++++++++-------- 4 files changed, 128 insertions(+), 72 deletions(-) diff --git a/src/osgEarth/TerrainOptions b/src/osgEarth/TerrainOptions index b478cda997..de631e656b 100644 --- a/src/osgEarth/TerrainOptions +++ b/src/osgEarth/TerrainOptions @@ -79,6 +79,8 @@ namespace osgEarth OE_OPTION(float, screenSpaceError, 0.0f); OE_OPTION(unsigned, maxTextureSize, 65536u); OE_OPTION(bool, visible, true); + OE_OPTION(bool, createTilesAsync, true); + OE_OPTION(bool, createTilesGrouped, true); virtual Config getConfig() const; private: @@ -272,6 +274,14 @@ namespace osgEarth void setVisible(const bool& value); const bool& getVisible() const; + //! Whether the engine should create child tiles asynchronously + void setCreateTilesAsync(const bool& value); + const bool& getCreateTilesAsync() const; + + //! Whether the engine should create all child tiles in a group + void setCreateTilesGrouped(const bool& value); + const bool& getCreateTilesGrouped() const; + TerrainOptionsAPI(); TerrainOptionsAPI(TerrainOptions*); TerrainOptionsAPI(const TerrainOptionsAPI&); diff --git a/src/osgEarth/TerrainOptions.cpp b/src/osgEarth/TerrainOptions.cpp index da574f7c6b..6464c3e285 100644 --- a/src/osgEarth/TerrainOptions.cpp +++ b/src/osgEarth/TerrainOptions.cpp @@ -76,6 +76,9 @@ TerrainOptions::getConfig() const conf.set("max_texture_size", maxTextureSize()); conf.set("visible", visible()); + conf.set("create_tiles_async", createTilesAsync()); + conf.set("create_tiles_grouped", createTilesGrouped()); + conf.set("expiration_range", minExpiryRange()); // legacy conf.set("expiration_threshold", minResidentTiles()); // legacy @@ -129,6 +132,9 @@ TerrainOptions::fromConfig(const Config& conf) conf.get("max_texture_size", maxTextureSize()); conf.get("visible", visible()); + conf.get("create_tiles_async", createTilesAsync()); + conf.get("create_tiles_grouped", createTilesGrouped()); + conf.get("expiration_range", minExpiryRange()); // legacy conf.get("expiration_threshold", minResidentTiles()); // legacy @@ -210,6 +216,8 @@ OE_OPTION_IMPL(TerrainOptionsAPI, unsigned, Concurrency, concurrency); OE_OPTION_IMPL(TerrainOptionsAPI, float, ScreenSpaceError, screenSpaceError); OE_OPTION_IMPL(TerrainOptionsAPI, unsigned, MaxTextureSize, maxTextureSize); OE_OPTION_IMPL(TerrainOptionsAPI, bool, Visible, visible); +OE_OPTION_IMPL(TerrainOptionsAPI, bool, CreateTilesAsync, createTilesAsync); +OE_OPTION_IMPL(TerrainOptionsAPI, bool, CreateTilesGrouped, createTilesGrouped); void TerrainOptionsAPI::setDriver(const std::string& value) diff --git a/src/osgEarthDrivers/engine_rex/TileNode b/src/osgEarthDrivers/engine_rex/TileNode index 344c74aa40..9720048f46 100644 --- a/src/osgEarthDrivers/engine_rex/TileNode +++ b/src/osgEarthDrivers/engine_rex/TileNode @@ -182,31 +182,35 @@ namespace osgEarth { namespace REX TileKey _key; osg::observer_ptr _parentTile; - osg::ref_ptr _surface; - osg::observer_ptr _context; - Threading::Mutex _mutex; - std::atomic _lastTraversalFrame; - double _lastTraversalTime; - float _lastTraversalRange; - bool _childrenReady; - mutable osg::Vec4f _tileKeyValue; - osg::Vec2f _morphConstants; - TileRenderModel _renderModel; - bool _empty; - bool _imageUpdatesActive; - TileKey _subdivideTestKey; - bool _doNotExpire; - int _revision; - bool _createChildAsync; + osg::ref_ptr _surface; + osg::observer_ptr _context; + Threading::Mutex _mutex; + std::atomic _lastTraversalFrame; + double _lastTraversalTime = 0.0; + float _lastTraversalRange = FLT_MAX; + bool _childrenReady = false; + mutable osg::Vec4f _tileKeyValue; + osg::Vec2f _morphConstants; + TileRenderModel _renderModel; + bool _empty = false; + bool _imageUpdatesActive = false; + TileKey _subdivideTestKey; + bool _doNotExpire = false; + int _revision = 0; std::atomic _loadPriority; + // for each job creating one child at a time: using CreateChildResult = osg::ref_ptr; std::vector> _createChildResults; + // for each job creating all children at once: + using CreateChildrenResult = std::vector>; + Future _createChildrenFutureResult; + using LoadQueue = std::queue; Mutexed _loadQueue; - unsigned _loadsInQueue; - const CreateTileManifest* _nextLoadManifestPtr; + unsigned _loadsInQueue = 0; + const CreateTileManifest* _nextLoadManifestPtr = nullptr; bool dirty() const { return _loadsInQueue > 0; diff --git a/src/osgEarthDrivers/engine_rex/TileNode.cpp b/src/osgEarthDrivers/engine_rex/TileNode.cpp index 05620b7f5a..140c06af6e 100644 --- a/src/osgEarthDrivers/engine_rex/TileNode.cpp +++ b/src/osgEarthDrivers/engine_rex/TileNode.cpp @@ -50,28 +50,13 @@ namespace }; } -TileNode::TileNode( - const TileKey& key, - TileNode* parent, - EngineContext* context, - Cancelable* progress) : - +TileNode::TileNode(const TileKey& key, TileNode* parent, EngineContext* context, Cancelable* progress) : _key(key), _parentTile(parent), _context(context), - _loadsInQueue(0u), - _childrenReady(false), - _lastTraversalTime(0.0), _lastTraversalFrame(0), - _lastTraversalRange(FLT_MAX), - _empty(false), // an "empty" node exists but has no geometry or children - _imageUpdatesActive(false), - _doNotExpire(false), - _revision(0), _mutex("TileNode(OE)"), _loadQueue("TileNode LoadQueue(OE)"), - _createChildAsync(true), - _nextLoadManifestPtr(nullptr), _loadPriority(0.0f) { OE_HARD_ASSERT(context != nullptr); @@ -89,12 +74,6 @@ TileNode::TileNode( double x = (double)_key.getTileX(); double y = (double)(th - _key.getTileY() - 1); - //_tileKeyValue.set( - // (float)(int)fmod(x, m), - // (float)(int)fmod(y, m), - // (float)_key.getLOD(), - // -1.0f); - _tileKeyValue.set( (float)(x-tw/2), //(int)fmod(x, m), (float)(y-th/2), // (int)fmod(y, m), @@ -673,36 +652,108 @@ TileNode::update(osg::NodeVisitor& nv) bool TileNode::createChildren() { - if (_createChildAsync) + if (_context->options().getCreateTilesAsync() == false) + { + // synchronous mode: do it now. + for (unsigned quadrant = 0; quadrant < 4; ++quadrant) + { + TileKey childkey = getKey().createChildKey(quadrant); + osg::ref_ptr child = createChild(childkey, nullptr); + addChild(child); + child->initializeData(); + child->refreshAllLayers(); + } + + return true; + } + + if (_context->options().getCreateTilesGrouped() == true) + { + // create all 4 children in a single job. + if (_createChildrenFutureResult.empty()) + { + EngineContext* context(_context.get()); + osg::observer_ptr tile_weakptr(this); + + auto createChildrenOperation = [context, tile_weakptr](Cancelable* state) + { + CreateChildrenResult result; + + osg::ref_ptr tile; + if (tile_weakptr.lock(tile) && !state->isCanceled()) + { + for (unsigned q = 0; q < 4; ++q) + { + auto childkey = tile->getKey().createChildKey(q); + result.emplace_back(tile->createChild(childkey, state)); + } + } + + if (state && state->isCanceled()) + result.clear(); + + return result; + }; + + Job job; + job.setArena(ARENA_CREATE_CHILD); + job.setName(_key.str()); + _createChildrenFutureResult = job.dispatch(createChildrenOperation); + } + + else if (_createChildrenFutureResult.available()) + { + // all 4 children MUST be present AND valid to continue + if (_createChildrenFutureResult.value().size() == 4 && + _createChildrenFutureResult.value()[0].valid() && + _createChildrenFutureResult.value()[1].valid() && + _createChildrenFutureResult.value()[2].valid() && + _createChildrenFutureResult.value()[3].valid()) + { + for (int i = 0; i < 4; ++i) + { + auto& child = _createChildrenFutureResult.value()[i]; + addChild(child); + child->initializeData(); + child->refreshAllLayers(); + } + } + + _createChildrenFutureResult.reset(); + } + + // true if the result is empty (i.e., the job is complete) + return _createChildrenFutureResult.empty(); + } + + else // if create each tile separately { + // create each child is a separate job. if (_createChildResults.empty()) { TileKey parentkey(_key); EngineContext* context(_context.get()); - for (unsigned quadrant = 0; quadrant < 4; ++quadrant) { TileKey childkey = getKey().createChildKey(quadrant); osg::observer_ptr tile_weakptr(this); auto createChildOperation = [context, tile_weakptr, childkey](Cancelable* state) - { - CreateChildResult result; + { + CreateChildResult result; - osg::ref_ptr tile; - if (tile_weakptr.lock(tile) && !state->isCanceled()) - result = tile->createChild(childkey, state); + osg::ref_ptr tile; + if (tile_weakptr.lock(tile) && !state->isCanceled()) + result = tile->createChild(childkey, state); - return result; - }; + return result; + }; Job job; job.setArena(ARENA_CREATE_CHILD); job.setName(childkey.str()); - _createChildResults.emplace_back( - job.dispatch(createChildOperation) - ); + _createChildResults.emplace_back(job.dispatch(createChildOperation)); } } @@ -729,21 +780,9 @@ TileNode::createChildren() _createChildResults.clear(); } } - } - else - { - for (unsigned quadrant = 0; quadrant < 4; ++quadrant) - { - TileKey childkey = getKey().createChildKey(quadrant); - osg::ref_ptr child = createChild(childkey, nullptr); - addChild(child); - child->initializeData(); - child->refreshAllLayers(); - } + return _createChildResults.empty(); } - - return _createChildResults.empty(); } TileNode* @@ -763,9 +802,7 @@ TileNode::createChild(const TileKey& childkey, Cancelable* progress) } void -TileNode::merge( - const TerrainTileModel* model, - const CreateTileManifest& manifest) +TileNode::merge(const TerrainTileModel* model, const CreateTileManifest& manifest) { bool newElevationData = false; const RenderBindings& bindings = _context->getRenderBindings(); @@ -1019,9 +1056,6 @@ TileNode::merge( bindingIndex, sharedLayer.texture(), sharedLayer.revision()); - //osg::Texture* tex = layerModel->getTexture(); - //int revision = layerModel->getRevision(); - //_renderModel.setSharedSampler(bindingIndex, tex, revision); uidsLoaded.insert(uid); } @@ -1329,6 +1363,7 @@ TileNode::removeSubTiles() } this->removeChildren(0, this->getNumChildren()); + _createChildrenFutureResult.abandon(); _createChildResults.clear(); } @@ -1388,7 +1423,6 @@ TileNode::updateNormalMap() { readThat(pixel, 0, t); writeThis(pixel, width-1, t); - //writeThis(readThat(0, t), width-1, t); } thisImage->dirty();