diff --git a/src/applications/CMakeLists.txt b/src/applications/CMakeLists.txt index bf6cd6fe15..1e5f722e1b 100644 --- a/src/applications/CMakeLists.txt +++ b/src/applications/CMakeLists.txt @@ -85,23 +85,25 @@ IF(NOT OSGEARTH_BUILD_PLATFORM_IPHONE) ADD_SUBDIRECTORY(osgearth_heatmap) ADD_SUBDIRECTORY(osgearth_collecttriangles) - IF(SILVERLINING_FOUND) - ADD_SUBDIRECTORY(osgearth_silverlining) - ENDIF(SILVERLINING_FOUND) - - IF(TRITON_FOUND) - ADD_SUBDIRECTORY(osgearth_triton) - ENDIF(TRITON_FOUND) - ENDIF(OSGEARTH_BUILD_EXAMPLES) IF(OSGEARTH_BUILD_TESTS) + SET(TARGET_DEFAULT_LABEL_PREFIX "Test") + SET(TARGET_DEFAULT_APPLICATION_FOLDER "Tests") add_subdirectory(osgearth_bindless) ADD_SUBDIRECTORY(osgearth_drawables) ADD_SUBDIRECTORY(osgearth_horizon) ADD_SUBDIRECTORY(osgearth_overlayviewer) ADD_SUBDIRECTORY(osgearth_shadercomp) ADD_SUBDIRECTORY(osgearth_windows) + + IF(SILVERLINING_FOUND) + ADD_SUBDIRECTORY(osgearth_silverlining) + ENDIF(SILVERLINING_FOUND) + + IF(TRITON_FOUND) + ADD_SUBDIRECTORY(osgearth_triton) + ENDIF(TRITON_FOUND) ENDIF(OSGEARTH_BUILD_TESTS) ELSE() diff --git a/src/applications/osgearth_bakefeaturetiles/osgearth_bakefeaturetiles.cpp b/src/applications/osgearth_bakefeaturetiles/osgearth_bakefeaturetiles.cpp index 60bd9647a4..20c3079f14 100644 --- a/src/applications/osgearth_bakefeaturetiles/osgearth_bakefeaturetiles.cpp +++ b/src/applications/osgearth_bakefeaturetiles/osgearth_bakefeaturetiles.cpp @@ -402,7 +402,7 @@ class TileListVisitor : public osgEarth::MultithreadedTileVisitor { } - virtual void run(const Profile* mapProfile) + void run(const Profile* mapProfile) override { // Start up the task service OE_INFO << "Starting " << _numThreads << " threads " << std::endl; @@ -419,7 +419,7 @@ class TileListVisitor : public osgEarth::MultithreadedTileVisitor this->handleTile(key); } - _group.join(); + _group->join(); } std::vector< TileKey > _keys; diff --git a/src/applications/osgearth_bindless/osgearth_bindless.cpp b/src/applications/osgearth_bindless/osgearth_bindless.cpp index e3aa83c9c4..4b422cddd0 100644 --- a/src/applications/osgearth_bindless/osgearth_bindless.cpp +++ b/src/applications/osgearth_bindless/osgearth_bindless.cpp @@ -53,6 +53,8 @@ int main_NV(int argc, char** argv) osg::ArgumentParser arguments(&argc, argv); osgViewer::Viewer viewer(arguments); + viewer.setRealizeOperation(new GL3RealizeOperation()); + MapNodeHelper().configureView(&viewer); if (arguments.read("--pause")) diff --git a/src/applications/osgearth_collecttriangles/osgearth_collecttriangles.cpp b/src/applications/osgearth_collecttriangles/osgearth_collecttriangles.cpp index 1f99b26ac0..b72222b149 100644 --- a/src/applications/osgearth_collecttriangles/osgearth_collecttriangles.cpp +++ b/src/applications/osgearth_collecttriangles/osgearth_collecttriangles.cpp @@ -490,7 +490,7 @@ void computeIntersectionsThreaded(osg::Node* node, std::vector< IntersectionQuer pool->set_concurrency(num_threads); // Poor man's parallel for - jobs::jobgroup intersections; + auto intersections = jobs::jobgroup::create(); //unsigned int workSize = 500; // Try to split the jobs evenly among the threads @@ -508,7 +508,7 @@ void computeIntersectionsThreaded(osg::Node* node, std::vector< IntersectionQuer { jobs::context context; context.pool = pool; - context.group = &intersections; + context.group = intersections; jobs::dispatch([node, curStart, curSize, &queries](Cancelable&) { computeIntersections(node, queries, curStart, curSize); @@ -525,7 +525,7 @@ void computeIntersectionsThreaded(osg::Node* node, std::vector< IntersectionQuer } } //std::cout << "Dispatched " << numJobs << " jobs" << std::endl; - intersections.join(); + intersections->join(); } diff --git a/src/osgEarth/TerrainOptions b/src/osgEarth/TerrainOptions index de631e656b..72f64dc4bd 100644 --- a/src/osgEarth/TerrainOptions +++ b/src/osgEarth/TerrainOptions @@ -66,12 +66,12 @@ namespace osgEarth OE_OPTION(float, tilePixelSize, 512.0f); OE_OPTION(float, heightFieldSkirtRatio, 0.0f); OE_OPTION(Color, color, Color::White); - OE_OPTION(bool, progressive, false); + OE_OPTION(bool, progressive, true); OE_OPTION(bool, useNormalMaps, true); OE_OPTION(bool, normalizeEdges, false); OE_OPTION(bool, morphTerrain, true); OE_OPTION(bool, morphImagery, true); - OE_OPTION(unsigned, mergesPerFrame, 20u); + OE_OPTION(unsigned, mergesPerFrame, ~0u); OE_OPTION(float, priorityScale, 1.0f); OE_OPTION(std::string, textureCompression, {}); OE_OPTION(unsigned, concurrency, 4u); @@ -114,15 +114,6 @@ namespace osgEarth void setMaxLOD(const unsigned& value); const unsigned& getMaxLOD() const; - //! (Legacy property) - //! The minimum level of detail to which the terrain should subdivide (no matter what). - //! If you leave this unset, the terrain will subdivide until the map layers - //! stop providing data (default behavior). If you set a value, the terrain will subdivide - //! to the specified LOD no matter what (and may continue farther if higher-resolution - //! data is available). - void setMinLOD(const unsigned& value); - const unsigned& getMinLOD() const; - //! (Legacy property) //! The lowest LOD to display. By default, the terrain begins at LOD 0. //! Set this to start the terrain tile mesh at a higher LOD. @@ -140,11 +131,7 @@ namespace osgEarth void setEnableBlending(const bool& value); const bool& getEnableBlending() const; - //! @deprecated - //! Whether to compress the normal maps before sending to the GPU - void setCompressNormalMaps(const bool& value); - const bool& getCompressNormalMaps() const; - + //! (Currently not used) //! Minimum level of detail at which to generate elevation-based normal maps, //! assuming normal maps have been activated. This mitigates the overhead of //! calculating normal maps for very high altitude scenes where they are no @@ -164,10 +151,6 @@ namespace osgEarth void setTessellationRange(const float& value); const float& getTessellationRange() const; - //! Whether to activate debugging mode - void setDebug(const bool& value); - const bool& getDebug() const; - //! Render bin number for the terrain void setRenderBinNumber(const int& value); const int& getRenderBinNumber() const; @@ -248,12 +231,6 @@ namespace osgEarth void setMergesPerFrame(const unsigned& value); const unsigned& getMergesPerFrame() const; - //! Scale factor for background loading priority of terrain tiles. - //! Default = 1.0. Make it higher to prioritize terrain loading over - //! other modules. - void setPriorityScale(const float& value); - const float& getPriorityScale() const; - //! Texture compression to use by default on terrain image textures void setTextureCompressionMethod(const std::string& method); const std::string& getTextureCompressionMethod() const; @@ -282,6 +259,32 @@ namespace osgEarth void setCreateTilesGrouped(const bool& value); const bool& getCreateTilesGrouped() const; + //! @deprecated + //! Scale factor for background loading priority of terrain tiles. + //! Default = 1.0. Make it higher to prioritize terrain loading over + //! other modules. + void setPriorityScale(const float& value); + const float& getPriorityScale() const; + + //! @deprecated + //! Whether to activate debugging mode + void setDebug(const bool& value); + const bool& getDebug() const; + + //! @deprecated + //! Whether to compress the normal maps before sending to the GPU + void setCompressNormalMaps(const bool& value); + const bool& getCompressNormalMaps() const; + + //! @deprecated + //! The minimum level of detail to which the terrain should subdivide (no matter what). + //! If you leave this unset, the terrain will subdivide until the map layers + //! stop providing data (default behavior). If you set a value, the terrain will subdivide + //! to the specified LOD no matter what (and may continue farther if higher-resolution + //! data is available). + void setMinLOD(const unsigned& value); + const unsigned& getMinLOD() const; + TerrainOptionsAPI(); TerrainOptionsAPI(TerrainOptions*); TerrainOptionsAPI(const TerrainOptionsAPI&); diff --git a/src/osgEarth/Threading b/src/osgEarth/Threading index 08852ddd9d..77af30e5a4 100644 --- a/src/osgEarth/Threading +++ b/src/osgEarth/Threading @@ -18,6 +18,7 @@ */ #pragma once #include +#include // bring in weejobs in the jobs namespace #define WEEJOBS_EXPORT OSGEARTH_EXPORT diff --git a/src/osgEarth/TileVisitor b/src/osgEarth/TileVisitor index 78e04890f9..6399ad8d8a 100644 --- a/src/osgEarth/TileVisitor +++ b/src/osgEarth/TileVisitor @@ -141,7 +141,7 @@ namespace osgEarth { namespace Util unsigned int _numThreads; - jobs::jobgroup _group; + std::shared_ptr _group; }; diff --git a/src/osgEarth/TileVisitor.cpp b/src/osgEarth/TileVisitor.cpp index 7e8d6df258..3975de75dd 100644 --- a/src/osgEarth/TileVisitor.cpp +++ b/src/osgEarth/TileVisitor.cpp @@ -239,6 +239,8 @@ MultithreadedTileVisitor::MultithreadedTileVisitor() : // We must do this to avoid an error message in OpenSceneGraph b/c the findWrapper method doesn't appear to be threadsafe. // This really isn't a big deal b/c this only effects data that is already cached. osgDB::ObjectWrapper* wrapper = osgDB::Registry::instance()->getObjectWrapperManager()->findWrapper("osg::Image"); + + _group = jobs::jobgroup::create(); } MultithreadedTileVisitor::MultithreadedTileVisitor(TileHandler* handler) : @@ -269,7 +271,7 @@ void MultithreadedTileVisitor::run(const Profile* mapProfile) // Produce the tiles TileVisitor::run( mapProfile ); - _group.join(); + _group->join(); } bool MultithreadedTileVisitor::handleTile(const TileKey& key) @@ -297,7 +299,7 @@ bool MultithreadedTileVisitor::handleTile(const TileKey& key) jobs::context job; job.name = "handleTile"; job.pool = jobs::get_pool(MTTV); - job.group = &_group; + job.group = _group; jobs::dispatch(task, job); diff --git a/src/osgEarth/weejobs.h b/src/osgEarth/weejobs.h index 960f15c324..6fa254dbf3 100644 --- a/src/osgEarth/weejobs.h +++ b/src/osgEarth/weejobs.h @@ -6,18 +6,18 @@ */ #pragma once #include -#include -#include +#include +#include #include +#include #include -#include -#include -#include +#include +#include +#include #include -#include -#include +#include -// OPTIONAL: Define WEEJOBS_EXPORT if you want to use this library from multiple modules (DLLs) + // OPTIONAL: Define WEEJOBS_EXPORT if you want to use this library from multiple modules (DLLs) #ifndef WEEJOBS_EXPORT #define WEEJOBS_EXPORT #endif @@ -386,7 +386,13 @@ namespace WEEJOBS_NAMESPACE * You can then call jobgroup::join() to wait for the whole group * to finish. */ - using jobgroup = detail::semaphore; + struct jobgroup : public detail::semaphore + { + static std::shared_ptr create() + { + return std::make_shared(); + } + }; /** * Context object you can pass to dispatch(...) to control aspects of @@ -397,7 +403,7 @@ namespace WEEJOBS_NAMESPACE std::string name; class jobpool* pool = nullptr; std::function priority = {}; - jobgroup* group = nullptr; + std::shared_ptr group = nullptr; }; /** @@ -532,34 +538,38 @@ namespace WEEJOBS_NAMESPACE // (Benchmark: https://stackoverflow.com/a/20365638/4218920) // Also note: it is indeed possible for the results of // priority() to change during the search. We don't care. - int index = -1; + //int index = -1; + std::list::iterator ptr = _queue.end(); float highest_priority = -FLT_MAX; - for (unsigned i = 0; i < _queue.size(); ++i) + for (auto iter = _queue.begin(); iter != _queue.end(); ++iter) { - float priority = _queue[i].ctx.priority != nullptr ? - _queue[i].ctx.priority() : + float priority = iter->ctx.priority != nullptr ? + iter->ctx.priority() : 0.0f; - if (index < 0 || priority > highest_priority) + if (ptr == _queue.end() || priority > highest_priority) { - index = i; + ptr = iter; highest_priority = priority; } } - if (index < 0) - index = 0; - next = std::move(_queue[index]); + if (ptr == _queue.end()) + ptr = _queue.begin(); + + next = std::move(*ptr); // _queue[index]); have_next = true; + _queue.erase(ptr); + // move the last element into the empty position: - if (index < _queue.size() - 1) - { - _queue[index] = std::move(_queue.back()); - } + //if (index < _queue.size() - 1) + //{ + // _queue[index] = std::move(_queue.back()); + //} // and remove the last element. - _queue.erase(_queue.end() - 1); + //_queue.erase(_queue.end() - 1); } } @@ -624,7 +634,8 @@ namespace WEEJOBS_NAMESPACE }; std::string _name; // pool name - std::vector _queue; // queued operations to run asynchronously + std::list _queue; + //std::vector _queue; // queued operations to run asynchronously mutable std::mutex _queueMutex; // protect access to the queue mutable std::mutex _quitMutex; // protects access to _done std::atomic _targetConcurrency; // target number of concurrent threads in the pool @@ -689,18 +700,9 @@ namespace WEEJOBS_NAMESPACE { inline runtime(); - inline void kill() - { - _alive = false; - - for (auto& pool : _pools) - if (pool) - pool->stop_threads(); + inline ~runtime(); - for (auto& pool : _pools) - if (pool) - pool->join_threads(); - } + inline void shutdown(); bool _alive = true; std::mutex _mutex; @@ -806,7 +808,7 @@ namespace WEEJOBS_NAMESPACE { if (queuedjob.ctx.group != nullptr) { - queuedjob.ctx.group->reset(); + queuedjob.ctx.group->release(); } } _queue.clear(); @@ -840,7 +842,7 @@ namespace WEEJOBS_NAMESPACE //! stop all threads, wait for them to exit, and shut down the system inline void shutdown() { - instance().kill(); + instance().shutdown(); } //! Whether the weejobs runtime is still alive (has not been shutdown) @@ -856,10 +858,29 @@ namespace WEEJOBS_NAMESPACE instance()._setThreadName = f; } - // internal inline detail::runtime::runtime() { - std::atexit(shutdown); + //nop + } + + inline detail::runtime::~runtime() + { + shutdown(); + } + + inline void detail::runtime::shutdown() + { + _alive = false; + + //std::cout << "stopping " << _pools.size() << " threads..." << std::endl; + for (auto& pool : _pools) + if (pool) + pool->stop_threads(); + + //std::cout << "joining " << _pools.size() << " threads..." << std::endl; + for (auto& pool : _pools) + if (pool) + pool->join_threads(); } // Use this macro ONCE in your application in a .cpp file to diff --git a/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp b/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp index 055af8e0e9..0fa1c9454e 100644 --- a/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp +++ b/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp @@ -573,10 +573,8 @@ RexTerrainEngineNode::refresh(bool forceDirty) this->ref(); // Load all the root key tiles. - jobs::jobgroup loadGroup; - jobs::context context; - context.group = &loadGroup; + context.group = jobs::jobgroup::create(); context.pool = jobs::get_pool(ARENA_LOAD_TILE); for (unsigned i = 0; i < keys.size(); ++i) @@ -603,7 +601,7 @@ RexTerrainEngineNode::refresh(bool forceDirty) } // wait for all loadSync calls to complete - loadGroup.join(); + context.group->join(); // release the self-ref. this->unref_nodelete(); diff --git a/src/osgEarthDrivers/engine_rex/TileNode.cpp b/src/osgEarthDrivers/engine_rex/TileNode.cpp index 3aac2adcf5..7f47631027 100644 --- a/src/osgEarthDrivers/engine_rex/TileNode.cpp +++ b/src/osgEarthDrivers/engine_rex/TileNode.cpp @@ -436,8 +436,8 @@ TileNode::cull(TerrainCuller* culler) // whether it is OK to load data (if necessary) bool canLoadData = _doNotExpire || - _key.getLOD() == _context->options().getFirstLOD() || - _key.getLOD() >= _context->options().getMinLOD(); + _key.getLOD() >= _context->options().getFirstLOD(); + //_key.getLOD() >= _context->options().getMinLOD(); // whether to accept the current surface node and not the children. bool canAcceptSurface = false;