Skip to content

Commit

Permalink
Engine: combine the createChild jobs into one job per 4 tile children…
Browse files Browse the repository at this point in the history
… instead of 4 jobs (one for each)
  • Loading branch information
gwaldron committed Feb 6, 2024
1 parent 3ee844c commit 45f4283
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 72 deletions.
10 changes: 10 additions & 0 deletions src/osgEarth/TerrainOptions
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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&);
Expand Down
8 changes: 8 additions & 0 deletions src/osgEarth/TerrainOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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)
Expand Down
40 changes: 22 additions & 18 deletions src/osgEarthDrivers/engine_rex/TileNode
Original file line number Diff line number Diff line change
Expand Up @@ -182,31 +182,35 @@ namespace osgEarth { namespace REX

TileKey _key;
osg::observer_ptr<TileNode> _parentTile;
osg::ref_ptr<SurfaceNode> _surface;
osg::observer_ptr<EngineContext> _context;
Threading::Mutex _mutex;
std::atomic<int> _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<SurfaceNode> _surface;
osg::observer_ptr<EngineContext> _context;
Threading::Mutex _mutex;
std::atomic<int> _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<float> _loadPriority;

// for each job creating one child at a time:
using CreateChildResult = osg::ref_ptr<TileNode>;
std::vector<Future<CreateChildResult>> _createChildResults;

// for each job creating all children at once:
using CreateChildrenResult = std::vector<osg::ref_ptr<TileNode>>;
Future<CreateChildrenResult> _createChildrenFutureResult;

using LoadQueue = std::queue<LoadTileDataOperationPtr>;
Mutexed<LoadQueue> _loadQueue;
unsigned _loadsInQueue;
const CreateTileManifest* _nextLoadManifestPtr;
unsigned _loadsInQueue = 0;
const CreateTileManifest* _nextLoadManifestPtr = nullptr;

bool dirty() const {
return _loadsInQueue > 0;
Expand Down
142 changes: 88 additions & 54 deletions src/osgEarthDrivers/engine_rex/TileNode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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),
Expand Down Expand Up @@ -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<TileNode> 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<TileNode> tile_weakptr(this);

auto createChildrenOperation = [context, tile_weakptr](Cancelable* state)
{
CreateChildrenResult result;

osg::ref_ptr<TileNode> 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<CreateChildrenResult>(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<TileNode> tile_weakptr(this);

auto createChildOperation = [context, tile_weakptr, childkey](Cancelable* state)
{
CreateChildResult result;
{
CreateChildResult result;

osg::ref_ptr<TileNode> tile;
if (tile_weakptr.lock(tile) && !state->isCanceled())
result = tile->createChild(childkey, state);
osg::ref_ptr<TileNode> 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<CreateChildResult>(createChildOperation)
);
_createChildResults.emplace_back(job.dispatch<CreateChildResult>(createChildOperation));
}
}

Expand All @@ -729,21 +780,9 @@ TileNode::createChildren()
_createChildResults.clear();
}
}
}

else
{
for (unsigned quadrant = 0; quadrant < 4; ++quadrant)
{
TileKey childkey = getKey().createChildKey(quadrant);
osg::ref_ptr<TileNode> child = createChild(childkey, nullptr);
addChild(child);
child->initializeData();
child->refreshAllLayers();
}
return _createChildResults.empty();
}

return _createChildResults.empty();
}

TileNode*
Expand All @@ -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();
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -1329,6 +1363,7 @@ TileNode::removeSubTiles()
}
this->removeChildren(0, this->getNumChildren());

_createChildrenFutureResult.abandon();
_createChildResults.clear();
}

Expand Down Expand Up @@ -1388,7 +1423,6 @@ TileNode::updateNormalMap()
{
readThat(pixel, 0, t);
writeThis(pixel, width-1, t);
//writeThis(readThat(0, t), width-1, t);
}

thisImage->dirty();
Expand Down

0 comments on commit 45f4283

Please sign in to comment.