diff --git a/src/osgEarth/Chonk b/src/osgEarth/Chonk index 5605e23875..c17df16c01 100644 --- a/src/osgEarth/Chonk +++ b/src/osgEarth/Chonk @@ -376,6 +376,8 @@ namespace osgEarth virtual const char* libraryName() const override { return "osgEarth"; } virtual const char* className() const override { return "ChonkRenderBin"; } + static void releaseSharedGLObjects(osg::State* state); + private: osg::ref_ptr _cullSS; diff --git a/src/osgEarth/Chonk.cpp b/src/osgEarth/Chonk.cpp index ef59ceff2e..e35ec07f68 100644 --- a/src/osgEarth/Chonk.cpp +++ b/src/osgEarth/Chonk.cpp @@ -1135,6 +1135,7 @@ ChonkDrawable::GLObjects::draw(osg::State& state) void ChonkDrawable::GLObjects::release() { + _ext = nullptr; _vao = nullptr; _commandBuf = nullptr; _instanceInputBuf = nullptr; @@ -1274,3 +1275,11 @@ ChonkRenderBin::drawImplementation( // dispatch. osgUtil::RenderBin::drawImplementation(ri, previous); } + +void +ChonkRenderBin::releaseSharedGLObjects(osg::State* state) +{ + auto proto = static_cast(osgUtil::RenderBin::getRenderBinPrototype("ChonkBin")); + if (proto->_cullSS.valid()) + proto->_cullSS->releaseGLObjects(state); +} diff --git a/src/osgEarth/GLUtils.cpp b/src/osgEarth/GLUtils.cpp index dfcfa1dd4c..4b20beec11 100644 --- a/src/osgEarth/GLUtils.cpp +++ b/src/osgEarth/GLUtils.cpp @@ -43,6 +43,8 @@ using namespace osgEarth; #define LC "[GLUtils] " +//#define USE_RECYCLING + #define OE_DEVEL OE_DEBUG #ifndef GL_LINE_SMOOTH @@ -78,31 +80,31 @@ namespace struct { typedef void (GL_APIENTRY* DebugProc)(GLenum, GLenum, GLuint, GLenum, GLsizei, const GLchar*, const void*); - - void (GL_APIENTRY * DebugMessageCallback)(DebugProc, const void*); - void (GL_APIENTRY * DebugMessageControl)(GLenum, GLenum, GLenum, GLsizei, const GLuint*, bool); - void (GL_APIENTRY * PushDebugGroup)(GLenum, GLuint, GLsizei, const char*); - void (GL_APIENTRY * PopDebugGroup)(void); + + void (GL_APIENTRY* DebugMessageCallback)(DebugProc, const void*); + void (GL_APIENTRY* DebugMessageControl)(GLenum, GLenum, GLenum, GLsizei, const GLuint*, bool); + void (GL_APIENTRY* PushDebugGroup)(GLenum, GLuint, GLsizei, const char*); + void (GL_APIENTRY* PopDebugGroup)(void); // NV_shader_buffer_load // https://developer.download.nvidia.com/opengl/specs/GL_NV_shader_buffer_load.txt - void (GL_APIENTRY * MakeNamedBufferResidentNV)(GLuint name, GLenum access); - void (GL_APIENTRY * MakeNamedBufferNonResidentNV)(GLuint name); - void (GL_APIENTRY * GetNamedBufferParameterui64vNV)(GLenum name, GLenum pname, GLuint64* params); + void (GL_APIENTRY* MakeNamedBufferResidentNV)(GLuint name, GLenum access); + void (GL_APIENTRY* MakeNamedBufferNonResidentNV)(GLuint name); + void (GL_APIENTRY* GetNamedBufferParameterui64vNV)(GLenum name, GLenum pname, GLuint64* params); - void (GL_APIENTRY * MakeBufferResidentNV)(GLuint name, GLenum access); - void (GL_APIENTRY * MakeBufferNonResidentNV)(GLuint name); - void (GL_APIENTRY * GetBufferParameterui64vNV)(GLenum target, GLenum pname, GLuint64* params); + void (GL_APIENTRY* MakeBufferResidentNV)(GLuint name, GLenum access); + void (GL_APIENTRY* MakeBufferNonResidentNV)(GLuint name); + void (GL_APIENTRY* GetBufferParameterui64vNV)(GLenum target, GLenum pname, GLuint64* params); - void (GL_APIENTRY * NamedBufferData)(GLuint name, GLsizeiptr size, const void* data, GLenum usage); - void (GL_APIENTRY * NamedBufferSubData)(GLuint name, GLintptr offset ,GLsizeiptr size, const void* data); - void*(GL_APIENTRY * MapNamedBuffer)(GLuint name, GLbitfield access); - void*(GL_APIENTRY * MapNamedBufferRange)(GLuint name, GLintptr offset, GLsizeiptr length, GLbitfield access); - void (GL_APIENTRY * UnmapNamedBuffer)(GLuint name); + void (GL_APIENTRY* NamedBufferData)(GLuint name, GLsizeiptr size, const void* data, GLenum usage); + void (GL_APIENTRY* NamedBufferSubData)(GLuint name, GLintptr offset, GLsizeiptr size, const void* data); + void* (GL_APIENTRY* MapNamedBuffer)(GLuint name, GLbitfield access); + void* (GL_APIENTRY* MapNamedBufferRange)(GLuint name, GLintptr offset, GLsizeiptr length, GLbitfield access); + void (GL_APIENTRY* UnmapNamedBuffer)(GLuint name); - void (GL_APIENTRY * CopyBufferSubData)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizei size); - void (GL_APIENTRY * CopyNamedBufferSubData)(GLuint readName, GLuint writeName, GLintptr readOffset, GLintptr writeOffset, GLsizei size); - void (GL_APIENTRY * GetNamedBufferSubData)(GLuint name, GLintptr offset, GLsizei size, void*); + void (GL_APIENTRY* CopyBufferSubData)(GLenum readTarget, GLenum writeTarget, GLintptr readOffset, GLintptr writeOffset, GLsizei size); + void (GL_APIENTRY* CopyNamedBufferSubData)(GLuint readName, GLuint writeName, GLintptr readOffset, GLintptr writeOffset, GLsizei size); + void (GL_APIENTRY* GetNamedBufferSubData)(GLuint name, GLintptr offset, GLsizei size, void*); bool useNamedBuffers; @@ -166,6 +168,10 @@ GLUtils::useNVGL(bool value) { OE_INFO << LC << "Using NVIDIA GL4 extensions" << std::endl; } + else + { + OE_INFO << LC << "Disabling NVIDIA GL4 extensions" << std::endl; + } } namespace @@ -196,7 +202,7 @@ GLUtils::getUniqueStateID(const osg::State& state) return 0; } -unsigned +unsigned GLUtils::getSharedContextID(const osg::State& state) { #ifdef OSGEARTH_SINGLE_GL_CONTEXT @@ -303,7 +309,7 @@ GLUtils::remove(osg::StateSet* stateSet, GLenum cap) return; #ifdef OSG_GL_FIXED_FUNCTION_AVAILABLE - switch(cap) + switch (cap) { case GL_LIGHTING: stateSet->removeMode(GL_LIGHTING); @@ -331,8 +337,8 @@ GLUtils::remove(osg::StateSet* stateSet, GLenum cap) } #endif - switch(cap) - { + switch (cap) + { case GL_LIGHTING: stateSet->removeDefine(OE_LIGHTING_DEFINE); break; @@ -730,7 +736,7 @@ GLObjectPool::releaseOrphans(const osg::GraphicsContext* gc) _objects.resize(_objects.size() - 1); } else - { + { bytes += object->size(); ++i; } @@ -915,6 +921,7 @@ GLBuffer::create( osg::State& state, GLsizei sizeHint) { +#ifdef USE_RECYCLING const GLObject::Compatible comp = [sizeHint](GLObject* obj) { return obj->ns() == GL_BUFFER && @@ -934,6 +941,9 @@ GLBuffer::create( object->_recyclable = true; } return object; +#else + return create(target, state); +#endif } void @@ -1242,10 +1252,11 @@ GLTexture::create(GLenum target, osg::State& state) GLTexture::Ptr GLTexture::create( - GLenum target, - osg::State& state, + GLenum target, + osg::State& state, const Profile& profileHint) { +#ifdef USE_RECYCLING const GLObject::Compatible comp = [profileHint](GLObject* obj) { return obj->ns() == GL_TEXTURE && @@ -1264,6 +1275,9 @@ GLTexture::create( object->_recyclable = true; } return object; +#else + return create(target, state); +#endif } void @@ -1313,7 +1327,7 @@ GLTexture::makeResident(const osg::State& state, bool toggle) else ext()->glMakeTextureHandleNonResident(_handle); - OE_DEVEL << "'" << id() << "' name=" << name() <<" resident=" << (toggle ? "yes" : "no") << std::endl; + OE_DEVEL << "'" << id() << "' name=" << name() << " resident=" << (toggle ? "yes" : "no") << std::endl; resident = toggle; } @@ -1367,13 +1381,13 @@ GLTexture::storage2D(const Profile& profile) profile._internalFormat, profile._width, profile._height); - + glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, profile._minFilter); glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, profile._magFilter); glTexParameteri(_target, GL_TEXTURE_WRAP_S, profile._wrapS); glTexParameteri(_target, GL_TEXTURE_WRAP_T, profile._wrapT); glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, profile._maxAnisotropy); - + // special trick: signed RGTC1 textures are compressed normals, so // swizzle the A component to be a zero so we can detect them. if (profile._internalFormat == GL_COMPRESSED_SIGNED_RED_RGTC1_EXT || @@ -1397,8 +1411,8 @@ GLTexture::storage3D(const Profile& profile) _profile = profile; // Profile(_target, mipLevels, internalFormat, s, t, r, 0); ext()->glTexStorage3D( - _target, - profile._numMipmapLevels, + _target, + profile._numMipmapLevels, profile._internalFormat, profile._width, profile._height, @@ -1474,7 +1488,7 @@ GLTexture::Ptr GLFBO::renderToTexture( GLsizei width, GLsizei height, - DrawFunction draw, + DrawFunction draw, osg::State& state) { // http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-14-render-to-texture/ @@ -1670,7 +1684,7 @@ ComputeImageSession::setImage(osg::Image* image) _image = image; _tex->setImage(image); _stateSet->setAttribute(new osg::BindImageTexture( - 0, _tex, osg::BindImageTexture::READ_WRITE, + 0, _tex, osg::BindImageTexture::READ_WRITE, image->getInternalTextureFormat(), 0, GL_TRUE)); image->dirty(); } diff --git a/src/osgEarth/MapNode.cpp b/src/osgEarth/MapNode.cpp index 32eb9b6075..cb52b30196 100644 --- a/src/osgEarth/MapNode.cpp +++ b/src/osgEarth/MapNode.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -977,11 +978,7 @@ MapNode::releaseGLObjects(osg::State* state) const for(const osg::Callback* ec = getEventCallback(); ec; ec = ec->getNestedCallback()) ec->releaseGLObjects(state); - // inform the GL object pools for this context - if (state) - { - GLObjectPool::releaseGLObjects(state); - } + ChonkRenderBin::releaseSharedGLObjects(state); osg::Group::releaseGLObjects(state); } diff --git a/src/osgEarth/TextureArena b/src/osgEarth/TextureArena index 8ea6c3f57b..7105f0dd0d 100644 --- a/src/osgEarth/TextureArena +++ b/src/osgEarth/TextureArena @@ -78,7 +78,7 @@ namespace osgEarth //! GL memory functions void compileGLObjects(osg::State&) const; void resizeGLObjectBuffers(unsigned); - void releaseGLObjects(osg::State*, bool force=false) const; + void releaseGLObjects(osg::State*, bool force = false) const; OE_PROPERTY(std::string, name); OE_PROPERTY(std::string, category); @@ -87,7 +87,7 @@ namespace osgEarth OE_PROPERTY(bool, clamp); OE_PROPERTY(bool, keepImage); OE_PROPERTY(unsigned, maxDim); - + OE_OPTION(URI, uri); OE_OPTION(GLenum, internalFormat); OE_OPTION(float, maxAnisotropy); @@ -128,7 +128,7 @@ namespace osgEarth * After that, you can call activate() or deactivate() on individual textures * to control their availability on the GPU. */ - #define OE_TEXTURE_ARENA_SA_TYPE_ID (osg::StateAttribute::Type)(osg::StateAttribute::CAPABILITY+8675309) +#define OE_TEXTURE_ARENA_SA_TYPE_ID (osg::StateAttribute::Type)(osg::StateAttribute::CAPABILITY+8675309) class OSGEARTH_EXPORT TextureArena : public osg::StateAttribute { @@ -165,7 +165,7 @@ namespace osgEarth //! Find the texture at index i. Texture::Ptr find(unsigned index) const; - + //! Number of textures registered size_t size() const { return _textures.size(); } @@ -191,22 +191,21 @@ namespace osgEarth private: //! disable copy - TextureArena(const TextureArena&, const osg::CopyOp&) { } + TextureArena(const TextureArena&, const osg::CopyOp&) { } void releaseGLObjects(osg::State*, bool force) const; // GL objects that can be shared across contexts struct GLObjects : public BindlessShareableGLObjects { - GLObjects() : _inUse(false), _lastAppliedFrame(-1) { } - bool _inUse; + bool _inUse = false; + bool _handleBufferDirty = true; + int _lastAppliedFrame = -1; + std::queue _toCompile; TextureVector _toRemove; - GLBuffer::Ptr _handleBuffer; std::vector _handles; - bool _dirty; - int _lastAppliedFrame; }; mutable osg::buffered_object _globjects; diff --git a/src/osgEarth/TextureArena.cpp b/src/osgEarth/TextureArena.cpp index 11441a5cc7..9e65b2daf9 100644 --- a/src/osgEarth/TextureArena.cpp +++ b/src/osgEarth/TextureArena.cpp @@ -42,12 +42,26 @@ using namespace osgEarth; #define OE_DEVEL OE_DEBUG +//#define DEEP_CLONE_IMAGE + +#ifdef OSGEARTH_SINGLE_GL_CONTEXT +#define MAX_CONTEXTS 1 +#else +#define MAX_CONTEXTS 16 +#endif + Texture::Ptr Texture::create(osg::Image* image, GLenum target) { Texture::Ptr object(new Texture(target)); if (image) + { +#ifdef DEEP_CLONE_IMAGE + object->osgTexture()->setImage(0, osg::clone(image, osg::CopyOp::DEEP_COPY_ALL)); +#else object->osgTexture()->setImage(0, image); +#endif + } return object; } @@ -59,7 +73,7 @@ Texture::create(osg::Texture* input) } Texture::Texture(GLenum target_) : - _globjects(16), + _globjects(MAX_CONTEXTS), _compress(true), _mipmap(true), _clamp(false), @@ -80,20 +94,23 @@ Texture::Texture(GLenum target_) : else { OE_HARD_ASSERT(false, "Invalid texture target"); } - if (osgTexture().valid()) - osgTexture()->setUnRefImageDataAfterApply( - Registry::instance()->unRefImageDataAfterApply().get()); - keepImage() = !Registry::instance()->unRefImageDataAfterApply().get(); + osgTexture()->setUnRefImageDataAfterApply(false); + keepImage() = true; } Texture::Texture(osg::Texture* input) : - _globjects(16), + _globjects(MAX_CONTEXTS), _compress(false), _maxDim(65536), - _osgTexture(input), _host(nullptr) { +#ifdef DEEP_CLONE_IMAGE + _osgTexture = osg::clone(input, osg::CopyOp::DEEP_COPY_ALL); +#else + _osgTexture = input; +#endif + target() = input->getTextureTarget(); mipmap() = @@ -122,7 +139,8 @@ Texture::Texture(osg::Texture* input) : uri() = URI(input->getImage(0)->getFileName()); } - keepImage() = !Registry::instance()->unRefImageDataAfterApply().get(); + osgTexture()->setUnRefImageDataAfterApply(false); + keepImage() = true; // !Registry::instance()->unRefImageDataAfterApply().get(); } Texture::~Texture() @@ -133,7 +151,8 @@ Texture::~Texture() bool Texture::isCompiled(const osg::State& state) const { - return GLObjects::get(_globjects, state)._gltexture != nullptr; + auto gltex = GLObjects::get(_globjects, state)._gltexture; + return gltex != nullptr && gltex->valid(); } bool @@ -143,7 +162,7 @@ Texture::needsCompile(const osg::State& state) const bool hasData = dataLoaded(); - if (gc._gltexture == nullptr && hasData == true) + if ((gc._gltexture == nullptr || !gc._gltexture->valid()) && hasData == true) return true; if (hasData == false) @@ -191,7 +210,7 @@ Texture::compileGLObjects(osg::State& state) const auto image = osgTexture()->getImage(0); // make sure we need to compile this - if (gc._gltexture != nullptr) + if (gc._gltexture != nullptr && gc._gltexture->valid()) { // hmm, it's already compiled. Does it need a recompile // because of a modified image? @@ -289,9 +308,9 @@ Texture::compileGLObjects(osg::State& state) const // debugging OE_DEVEL << LC - << "Texture::compileGLObjects '" << gc._gltexture->id() - << "' name=" << gc._gltexture->name() - << " handle=" << gc._gltexture->handle(state) << std::endl; + << "Texture::compileGLObjects '" << name() << "'" << std::endl; // << gc._gltexture->id() << "'" << std::endl; + //<< "' name=" << gc._gltexture->name() + //<< " handle=" << gc._gltexture->handle(state) << std::endl; bool compressed = image->isCompressed(); @@ -331,6 +350,8 @@ Texture::compileGLObjects(osg::State& state) const unsigned char* dataptr = image->getMipmapData(mipLevel); + + if (compressed) { gc._gltexture->compressedSubImage2D( @@ -418,7 +439,7 @@ Texture::makeResident(const osg::State& state, bool toggle) const { auto& gc = GLObjects::get(_globjects, state); - if (gc._gltexture != nullptr) + if (gc._gltexture != nullptr && gc._gltexture->valid()) { gc._gltexture->makeResident(state, toggle); @@ -460,19 +481,20 @@ Texture::releaseGLObjects(osg::State* state, bool force) const if (gc._gltexture != nullptr) { // debugging - OE_DEVEL << LC - << "Texture::releaseGLObjects '" << gc._gltexture->id() - << "' name=" << gc._gltexture->name() - << " handle=" << gc._gltexture->handle(*state) << std::endl; + OE_DEVEL << LC + << "Texture::releaseGLObjects '" << name() << "'" << std::endl; + //<< "' name=" << gc._gltexture->name() + //<< " handle=" << gc._gltexture->handle(*state) << std::endl; - // will activate the releaser + // will activate the releaser + gc._gltexture->release(); // redundant? gc._gltexture = nullptr; } } else { // rely on the Releaser to get around to it - for(unsigned i=0; i< _globjects.size(); ++i) + for (unsigned i = 0; i < _globjects.size(); ++i) { // will activate the releaser(s) _globjects[i]._gltexture = nullptr; @@ -684,7 +706,7 @@ TextureArena::add(Texture::Ptr tex, const osgDB::Options* readOptions) } // add to all existing GCs: - for(unsigned i=0; i< _globjects.size(); ++i) + for (unsigned i = 0; i < _globjects.size(); ++i) { if (_globjects[i]._inUse) _globjects[i]._toCompile.push(index); @@ -761,7 +783,7 @@ TextureArena::flush() ScopedMutexLock lock(_m); - for(unsigned i=0; i<_textures.size(); ++i) + for (unsigned i = 0; i < _textures.size(); ++i) { purgeTextureIfOrphaned_no_lock(i); } @@ -818,14 +840,17 @@ TextureArena::apply(osg::State& state) const gc._handleBuffer->debugLabel("TextureArena", "Handle LUT"); gc._handleBuffer->unbind(); - gc._dirty = true; + // zero out all the handles so we can re-upload them + for (auto& handle : gc._handles) + handle = 0; + + gc._handleBufferDirty = true; } // refresh the handles buffer if necessary: if (_textures.size() > gc._handles.size()) { - size_t aligned_size = gc._handleBuffer->align(_textures.size() * sizeof(gc._handles[0])) - / sizeof(gc._handles[0]); + size_t aligned_size = gc._handleBuffer->align(_textures.size() * sizeof(GLuint64)) / sizeof(GLuint64); unsigned int previousSize = gc._handles.size(); @@ -834,7 +859,7 @@ TextureArena::apply(osg::State& state) const { gc._handles[i] = 0; } - gc._dirty = true; + gc._handleBufferDirty = true; } #if !defined(OSGEARTH_SINGLE_GL_CONTEXT) @@ -878,11 +903,10 @@ TextureArena::apply(osg::State& state) const if (gc._handles[index] != handle) { gc._handles[index] = handle; - gc._dirty = true; } // mark the GC to re-upload its LUT - gc._dirty = true; + gc._handleBufferDirty = true; } } @@ -896,10 +920,10 @@ TextureArena::apply(osg::State& state) const } // upload to GPU if it changed: - if (gc._dirty) + if (gc._handleBufferDirty) { gc._handleBuffer->uploadData(gc._handles); - gc._dirty = false; + gc._handleBufferDirty = false; } gc._handleBuffer->bindBufferBase(_bindingPoint); @@ -942,7 +966,7 @@ TextureArena::resizeGLObjectBuffers(unsigned maxSize) _globjects.resize(maxSize); } - for(auto& tex : _textures) + for (auto& tex : _textures) { if (tex) tex->resizeGLObjectBuffers(maxSize); @@ -960,6 +984,8 @@ TextureArena::releaseGLObjects(osg::State* state, bool force) const { ScopedMutexLock lock(_m); + OE_DEVEL << LC << "releaseGLObjects on arena " << getName() << std::endl; + if (state) { auto& gc = GLObjects::get(_globjects, *state); @@ -990,7 +1016,7 @@ TextureArena::releaseGLObjects(osg::State* state, bool force) const for (unsigned i = 0; i < _globjects.size(); ++i) { GLObjects& gc = _globjects[i]; - if(gc._inUse) + if (gc._inUse) { gc._handleBuffer = nullptr; gc._handles.resize(0); diff --git a/src/osgEarthDrivers/engine_rex/EngineContext.cpp b/src/osgEarthDrivers/engine_rex/EngineContext.cpp index 1de0937f71..eb767507d9 100644 --- a/src/osgEarthDrivers/engine_rex/EngineContext.cpp +++ b/src/osgEarthDrivers/engine_rex/EngineContext.cpp @@ -28,14 +28,14 @@ using namespace osgEarth; #define LC "[EngineContext] " EngineContext::EngineContext( - const Map* map, - TerrainEngineNode* terrainEngine, - GeometryPool* geometryPool, - Merger* merger, + const Map* map, + TerrainEngineNode* terrainEngine, + GeometryPool* geometryPool, + Merger* merger, TileNodeRegistry::Ptr tiles, - const RenderBindings& renderBindings, - const SelectionInfo& selectionInfo, - const FrameClock* clock) : + const RenderBindings& renderBindings, + const SelectionInfo& selectionInfo, + const FrameClock* clock) : _map(map), _terrainEngine(terrainEngine), @@ -55,6 +55,7 @@ EngineContext::EngineContext( // create a bindless texture arena and set it to automatically // release textures that the terrain no longer references. _textures = new TextureArena(); + _textures->setName("REX Terrain Engine"); _textures->setBindingPoint(29); // TODO _textures->setAutoRelease(true); @@ -64,7 +65,7 @@ EngineContext::EngineContext( Registry::instance()->getMaxTextureSize()); _textures->setMaxTextureSize(maxSize); - + } osg::ref_ptr diff --git a/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp b/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp index 235bed5264..962273b116 100644 --- a/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp +++ b/src/osgEarthDrivers/engine_rex/RexTerrainEngineNode.cpp @@ -63,10 +63,10 @@ namespace RexTerrainEngineNodeMapCallbackProxy(RexTerrainEngineNode* node) : _node(node) { } osg::observer_ptr _node; - void onMapModelChanged( const MapModelChange& change ) override { + void onMapModelChanged(const MapModelChange& change) override { osg::ref_ptr node; - if ( _node.lock(node) ) - node->onMapModelChanged( change ); + if (_node.lock(node)) + node->onMapModelChanged(change); } }; @@ -111,7 +111,7 @@ namespace Layer* layer = _map->getLayerByUID(pass.sourceUID()); if (layer == nullptr || layer->isOpen() == false) { - model._passes.erase(model._passes.begin()+p); + model._passes.erase(model._passes.begin() + p); --p; _count++; } @@ -127,12 +127,12 @@ namespace //------------------------------------------------------------------------ RexTerrainEngineNode::RexTerrainEngineNode() : - TerrainEngineNode ( ), - _terrain ( 0L ), - _batchUpdateInProgress( false ), - _refreshRequired ( false ), - _stateUpdateRequired ( false ), - _renderModelUpdateRequired( false ), + TerrainEngineNode(), + _terrain(0L), + _batchUpdateInProgress(false), + _refreshRequired(false), + _stateUpdateRequired(false), + _renderModelUpdateRequired(false), _morphTerrainSupported(true), _frameLastUpdated(0u), _ppUID(0) @@ -220,6 +220,9 @@ RexTerrainEngineNode::releaseGLObjects(osg::State* state) const } } + if (_engineContext.valid()) + _engineContext->_textures->releaseGLObjects(state); + TerrainEngineNode::releaseGLObjects(state); } @@ -475,7 +478,7 @@ RexTerrainEngineNode::invalidateRegion( { GeoExtent extentLocal = extent; - if ( extent.isValid() && !extent.getSRS()->isHorizEquivalentTo(this->getMap()->getSRS()) ) + if (extent.isValid() && !extent.getSRS()->isHorizEquivalentTo(this->getMap()->getSRS())) { extent.transform(this->getMap()->getSRS(), extentLocal); } @@ -489,7 +492,7 @@ RexTerrainEngineNode::invalidateRegion( LayerVector layers; _map->getLayers(layers); - for(LayerVector::const_iterator i=layers.begin(); i != layers.end(); ++i) + for (LayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i) { manifest.insert(i->get()); } @@ -509,7 +512,7 @@ RexTerrainEngineNode::invalidateRegion( { GeoExtent extentLocal = extent; - if ( extent.isValid() && !extent.getSRS()->isHorizEquivalentTo(this->getMap()->getSRS()) ) + if (extent.isValid() && !extent.getSRS()->isHorizEquivalentTo(this->getMap()->getSRS())) { extent.transform(this->getMap()->getSRS(), extentLocal); } @@ -520,7 +523,7 @@ RexTerrainEngineNode::invalidateRegion( // so that the visible LOD gets updated first: manifest.setProgressive(false); - for(std::vector::const_iterator i = layers.begin(); + for (std::vector::const_iterator i = layers.begin(); i != layers.end(); ++i) { @@ -537,7 +540,7 @@ RexTerrainEngineNode::invalidateRegion( void RexTerrainEngineNode::refresh(bool forceDirty) { - if ( _batchUpdateInProgress ) + if (_batchUpdateInProgress) { _refreshRequired = true; } @@ -649,16 +652,16 @@ RexTerrainEngineNode::setupRenderBindings() _renderBindings.resize(SamplerBinding::SHARED); SamplerBinding& color = _renderBindings[SamplerBinding::COLOR]; - color.usage() = SamplerBinding::COLOR; + color.usage() = SamplerBinding::COLOR; color.samplerName() = "oe_layer_tex"; - color.matrixName() = "oe_layer_texMatrix"; + color.matrixName() = "oe_layer_texMatrix"; color.setDefaultTexture(new osg::Texture2D(ImageUtils::createEmptyImage(1, 1))); color.getDefaultTexture()->setName("rex default color"); if (!GLUtils::useNVGL()) - getResources()->reserveTextureImageUnit( color.unit(), "Terrain Color" ); + getResources()->reserveTextureImageUnit(color.unit(), "Terrain Color"); - if(this->elevationTexturesRequired()) + if (this->elevationTexturesRequired()) { SamplerBinding& elevation = _renderBindings[SamplerBinding::ELEVATION]; elevation.usage() = SamplerBinding::ELEVATION; @@ -766,7 +769,7 @@ RexTerrainEngineNode::cacheAllLayerExtentsInMapSRS() // Only call during update LayerVector layers; getMap()->getLayers(layers); - for(LayerVector::const_iterator i = layers.begin(); + for (LayerVector::const_iterator i = layers.begin(); i != layers.end(); ++i) { @@ -832,7 +835,7 @@ RexTerrainEngineNode::cull_traverse(osg::NodeVisitor& nv) } } - for(auto layerDrawable : culler._terrain._layerList) + for (auto layerDrawable : culler._terrain._layerList) { if (!layerDrawable->_tiles.empty()) { @@ -1049,7 +1052,7 @@ RexTerrainEngineNode::traverse(osg::NodeVisitor& nv) } } - else if ( nv.getVisitorType() == nv.CULL_VISITOR ) + else if (nv.getVisitorType() == nv.CULL_VISITOR) { _updatedThisFrame.exchange(false); _clock.cull(); @@ -1058,20 +1061,20 @@ RexTerrainEngineNode::traverse(osg::NodeVisitor& nv) else { - TerrainEngineNode::traverse( nv ); + TerrainEngineNode::traverse(nv); } } unsigned int RexTerrainEngineNode::computeSampleSize(unsigned int levelOfDetail) { - unsigned maxLevel = osg::minimum(options().maxLOD().get(), 19u ); // beyond LOD 19 or 20, morphing starts to lose precision. + unsigned maxLevel = osg::minimum(options().maxLOD().get(), 19u); // beyond LOD 19 or 20, morphing starts to lose precision. unsigned int meshSize = options().tileSize().get(); unsigned int sampleSize = meshSize; int level = maxLevel; // make sure it's signed for the loop below to work - while( level >= 0 && levelOfDetail != level) + while (level >= 0 && levelOfDetail != level) { sampleSize = sampleSize * 2 - 1; level--; @@ -1080,15 +1083,15 @@ RexTerrainEngineNode::computeSampleSize(unsigned int levelOfDetail) return sampleSize; } -osg::Vec3d getWorld( const GeoHeightField& geoHF, unsigned int c, unsigned int r) +osg::Vec3d getWorld(const GeoHeightField& geoHF, unsigned int c, unsigned int r) { double x = geoHF.getExtent().xMin() + (double)c * geoHF.getXInterval(); double y = geoHF.getExtent().yMin() + (double)r * geoHF.getYInterval(); - double h = geoHF.getHeightField()->getHeight(c,r); + double h = geoHF.getHeightField()->getHeight(c, r); osg::Vec3d world; - GeoPoint point(geoHF.getExtent().getSRS(), x, y, h ); - point.toWorld( world ); + GeoPoint point(geoHF.getExtent().getSRS(), x, y, h); + point.toWorld(world); return world; } @@ -1099,34 +1102,34 @@ osg::Node* renderHeightField(const GeoHeightField& geoHF) GeoPoint centroid = geoHF.getExtent().getCentroid(); osg::Matrix world2local, local2world; - centroid.createWorldToLocal( world2local ); - local2world.invert( world2local ); + centroid.createWorldToLocal(world2local); + local2world.invert(world2local); - mt->setMatrix( local2world ); + mt->setMatrix(local2world); osg::Geometry* geometry = new osg::Geometry; geometry->setName("REX height field"); geometry->setUseVertexBufferObjects(true); osg::Geode* geode = new osg::Geode; - geode->addDrawable( geometry ); - mt->addChild( geode ); + geode->addDrawable(geometry); + mt->addChild(geode); osg::Vec3Array* verts = new osg::Vec3Array; - geometry->setVertexArray( verts ); + geometry->setVertexArray(verts); for (unsigned int c = 0; c < geoHF.getHeightField()->getNumColumns() - 1; c++) { for (unsigned int r = 0; r < geoHF.getHeightField()->getNumRows() - 1; r++) { // Add two triangles - verts->push_back( getWorld( geoHF, c, r ) * world2local ); - verts->push_back( getWorld( geoHF, c + 1, r ) * world2local ); - verts->push_back( getWorld( geoHF, c + 1, r + 1) * world2local ); + verts->push_back(getWorld(geoHF, c, r) * world2local); + verts->push_back(getWorld(geoHF, c + 1, r) * world2local); + verts->push_back(getWorld(geoHF, c + 1, r + 1) * world2local); - verts->push_back( getWorld( geoHF, c, r ) * world2local ); - verts->push_back( getWorld( geoHF, c + 1, r + 1) * world2local ); - verts->push_back( getWorld( geoHF, c, r + 1) * world2local ); + verts->push_back(getWorld(geoHF, c, r) * world2local); + verts->push_back(getWorld(geoHF, c + 1, r + 1) * world2local); + verts->push_back(getWorld(geoHF, c, r + 1) * world2local); } } geode->setCullingActive(false); @@ -1135,7 +1138,7 @@ osg::Node* renderHeightField(const GeoHeightField& geoHF) geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLES, 0, verts->size())); osg::Vec4ubArray* colors = new osg::Vec4ubArray(); - colors->push_back(osg::Vec4ub(255,0,0,255)); + colors->push_back(osg::Vec4ub(255, 0, 0, 255)); geometry->setColorArray(colors, osg::Array::BIND_OVERALL); mt->getOrCreateStateSet()->setRenderBinDetails(99, "RenderBin"); @@ -1143,21 +1146,21 @@ osg::Node* renderHeightField(const GeoHeightField& geoHF) } void -RexTerrainEngineNode::onMapModelChanged( const MapModelChange& change ) +RexTerrainEngineNode::onMapModelChanged(const MapModelChange& change) { - if ( change.getAction() == MapModelChange::BEGIN_BATCH_UPDATE ) + if (change.getAction() == MapModelChange::BEGIN_BATCH_UPDATE) { _batchUpdateInProgress = true; } - else if ( change.getAction() == MapModelChange::END_BATCH_UPDATE ) + else if (change.getAction() == MapModelChange::END_BATCH_UPDATE) { _batchUpdateInProgress = false; - if ( _refreshRequired ) + if (_refreshRequired) refresh(); - if ( _stateUpdateRequired ) + if (_stateUpdateRequired) updateState(); } @@ -1165,10 +1168,10 @@ RexTerrainEngineNode::onMapModelChanged( const MapModelChange& change ) { // dispatch the change handler - if ( change.getLayer() ) + if (change.getLayer()) { // then apply the actual change: - switch( change.getAction() ) + switch (change.getAction()) { case MapModelChange::ADD_LAYER: case MapModelChange::OPEN_LAYER: @@ -1232,12 +1235,12 @@ RexTerrainEngineNode::addSurfaceLayer(Layer* layer) if (imageLayer) { // for a shared layer, allocate a shared image unit if necessary. - if ( imageLayer->isShared() ) + if (imageLayer->isShared()) { if (!imageLayer->sharedImageUnit().isSet() && !GLUtils::useNVGL()) { int temp; - if ( getResources()->reserveTextureImageUnit(temp, imageLayer->getName().c_str()) ) + if (getResources()->reserveTextureImageUnit(temp, imageLayer->getName().c_str())) { imageLayer->sharedImageUnit() = temp; //OE_INFO << LC << "Image unit " << temp << " assigned to shared layer " << imageLayer->getName() << std::endl; @@ -1249,7 +1252,7 @@ RexTerrainEngineNode::addSurfaceLayer(Layer* layer) } // Build a sampler binding for the shared layer. - if ( imageLayer->sharedImageUnit().isSet() || GLUtils::useNVGL() ) + if (imageLayer->sharedImageUnit().isSet() || GLUtils::useNVGL()) { // Find the next empty SHARED slot: unsigned newIndex = SamplerBinding::SHARED; @@ -1258,11 +1261,11 @@ RexTerrainEngineNode::addSurfaceLayer(Layer* layer) // Put the new binding there: SamplerBinding& newBinding = _renderBindings[newIndex]; - newBinding.usage() = SamplerBinding::SHARED; - newBinding.sourceUID() = imageLayer->getUID(); - newBinding.unit() = imageLayer->sharedImageUnit().get(); + newBinding.usage() = SamplerBinding::SHARED; + newBinding.sourceUID() = imageLayer->getUID(); + newBinding.unit() = imageLayer->sharedImageUnit().get(); newBinding.samplerName() = imageLayer->getSharedTextureUniformName(); - newBinding.matrixName() = imageLayer->getSharedTextureMatrixUniformName(); + newBinding.matrixName() = imageLayer->getSharedTextureMatrixUniformName(); OE_INFO << LC << "Shared Layer \"" << imageLayer->getName() << "\" : sampler=\"" << newBinding.samplerName() << "\", " @@ -1287,7 +1290,7 @@ RexTerrainEngineNode::addSurfaceLayer(Layer* layer) } else { - tex = new osg::Texture2D(ImageUtils::createEmptyImage(1,1)); + tex = new osg::Texture2D(ImageUtils::createEmptyImage(1, 1)); } tex->setName("default:" + imageLayer->getName()); tex->setUnRefImageDataAfterApply(Registry::instance()->unRefImageDataAfterApply().get()); @@ -1319,9 +1322,9 @@ RexTerrainEngineNode::addSurfaceLayer(Layer* layer) void -RexTerrainEngineNode::removeImageLayer( ImageLayer* layerRemoved ) +RexTerrainEngineNode::removeImageLayer(ImageLayer* layerRemoved) { - if ( layerRemoved ) + if (layerRemoved) { // release its layer drawable _persistent.scoped_lock([&]() { @@ -1330,11 +1333,11 @@ RexTerrainEngineNode::removeImageLayer( ImageLayer* layerRemoved ) }); // for a shared layer, release the shared image unit. - if ( layerRemoved->isOpen() && layerRemoved->isShared() ) + if (layerRemoved->isOpen() && layerRemoved->isShared()) { - if ( layerRemoved->sharedImageUnit().isSet() ) + if (layerRemoved->sharedImageUnit().isSet()) { - getResources()->releaseTextureImageUnit( *layerRemoved->sharedImageUnit() ); + getResources()->releaseTextureImageUnit(*layerRemoved->sharedImageUnit()); layerRemoved->sharedImageUnit().unset(); } @@ -1383,7 +1386,7 @@ RexTerrainEngineNode::addElevationLayer(Layer* layer) } void -RexTerrainEngineNode::removeElevationLayer( Layer* layer) +RexTerrainEngineNode::removeElevationLayer(Layer* layer) { // only need to refresh is the elevation layer is visible. if (layer) @@ -1459,7 +1462,7 @@ RexTerrainEngineNode::updateState() _terrainSS->addUniform(new osg::Uniform( "oe_tile_elevTexelCoeff", - osg::Vec2f((size - (2.0*bias)) / size, bias / size))); + osg::Vec2f((size - (2.0 * bias)) / size, bias / size))); } } @@ -1563,7 +1566,7 @@ RexTerrainEngineNode::updateState() // special object ID that denotes the terrain surface. _surfaceSS->addUniform(new osg::Uniform( - Registry::objectIndex()->getObjectIDUniformName().c_str(), + Registry::objectIndex()->getObjectIDUniformName().c_str(), OSGEARTH_OBJECTID_TERRAIN)); } @@ -1581,7 +1584,7 @@ RexTerrainEngineNode::updateState() void RexTerrainEngineNode::installColorFilters( VirtualProgram* surfaceVP) -{ +{ // TODO: DEPRECATE THESE bool haveColorFilters = false; { diff --git a/src/osgEarthProcedural/BiomeLayer b/src/osgEarthProcedural/BiomeLayer index 9c3532a929..9bb5874863 100644 --- a/src/osgEarthProcedural/BiomeLayer +++ b/src/osgEarthProcedural/BiomeLayer @@ -106,7 +106,7 @@ namespace osgEarth bool operator < (const BiomeSample& rhs) const { - OE_OPTION_LESS(biomeid, rhs.biomeid); + OE_OPTION_LESS(biomeid, rhs.biomeid); return false; } @@ -115,20 +115,20 @@ namespace osgEarth /** - * BiomeLayer creates rasters that encode Biome indices. + * BiomeLayer creates rasters that encode Biome indices. * * Each Biome has an associated integer index, corresponding to the order * in which it appears in the biome catalog. (NB: This index is totally * transparent to the user, and has no relationship to the Biome ID.) - * For a given TileKey, this layer will create a raster for which each + * For a given TileKey, this layer will create a raster for which each * pixel holds an index corresponding to a specific Biome. * * At runtime this object will scan each raster, determine which Biomes * are currently visible, and tell the BiomeManager to load the corresponding * assets. */ - class OSGEARTHPROCEDURAL_EXPORT BiomeLayer : - public ImageLayer, + class OSGEARTHPROCEDURAL_EXPORT BiomeLayer : + public ImageLayer, public osg::Observer { public: @@ -187,25 +187,29 @@ namespace osgEarth public: // Layer - virtual void addedToMap(const Map*) override; + void addedToMap(const Map*) override; - virtual void removedFromMap(const Map*) override; + void removedFromMap(const Map*) override; protected: // Layer - virtual void init() override; + void init() override; + + Status openImplementation() override; - virtual Status openImplementation() override; + Status closeImplementation() override; - virtual Status closeImplementation() override; + void resizeGLObjectBuffers(unsigned) override; + + void releaseGLObjects(osg::State*) const override; protected: // ImageLayer - virtual GeoImage createImageImplementation( - const TileKey& key, + GeoImage createImageImplementation( + const TileKey& key, ProgressCallback* progress) const override; - virtual void postCreateImageImplementation( + void postCreateImageImplementation( GeoImage& createdImage, const TileKey& key, ProgressCallback* progress) const override; diff --git a/src/osgEarthProcedural/BiomeLayer.cpp b/src/osgEarthProcedural/BiomeLayer.cpp index 79a6ea3d96..9ab1dfc7fc 100644 --- a/src/osgEarthProcedural/BiomeLayer.cpp +++ b/src/osgEarthProcedural/BiomeLayer.cpp @@ -419,8 +419,8 @@ BiomeLayer::createImageImplementation( std::vector sorted = sample->traits(); if (sorted.size() > 1) std::sort(sorted.begin(), sorted.end()); - - std::string implicit_biome_id = + + std::string implicit_biome_id = biome->id() + "." + AssetTraits::toString(sorted); const Biome* implicit_biome = getBiomeCatalog()->getBiome(implicit_biome_id); @@ -568,3 +568,19 @@ BiomeLayer::objectDeleted(void* value) _tracker.erase(token); }); } + +void +BiomeLayer::resizeGLObjectBuffers(unsigned maxsize) +{ + auto textures = _biomeMan.getTextures(); + if (textures) + textures->resizeGLObjectBuffers(maxsize); +} + +void +BiomeLayer::releaseGLObjects(osg::State* state) const +{ + auto textures = _biomeMan.getTextures(); + if (textures) + textures->releaseGLObjects(state); +} diff --git a/src/osgEarthProcedural/TextureSplattingLayer.cpp b/src/osgEarthProcedural/TextureSplattingLayer.cpp index 9ffdab13a4..cdad33a5c8 100644 --- a/src/osgEarthProcedural/TextureSplattingLayer.cpp +++ b/src/osgEarthProcedural/TextureSplattingLayer.cpp @@ -213,7 +213,7 @@ TextureSplattingLayer::prepareForRendering(TerrainEngine* engine) int ptr0 = 0; int ptr1 = assets.getMaterials().size(); - for(auto& material : assets.getMaterials()) + for (auto& material : assets.getMaterials()) { auto t0 = std::chrono::steady_clock::now(); @@ -306,8 +306,8 @@ TextureSplattingLayer::buildStateSets() getLifeMapLayer()->getSharedTextureMatrixUniformName()); terrain_shaders.load( - vp, - terrain_shaders.TextureSplatting, + vp, + terrain_shaders.TextureSplatting, getReadOptions()); // General purpose define indicating that this layer sets PBR values. @@ -419,10 +419,16 @@ void TextureSplattingLayer::resizeGLObjectBuffers(unsigned maxSize) { VisibleLayer::resizeGLObjectBuffers(maxSize); + + if (_materials && _materials->_arena.valid()) + _materials->_arena->resizeGLObjectBuffers(maxSize); } void TextureSplattingLayer::releaseGLObjects(osg::State* state) const { VisibleLayer::releaseGLObjects(state); + + if (_materials && _materials->_arena.valid()) + _materials->_arena->releaseGLObjects(state); } diff --git a/src/osgEarthProcedural/VegetationLayer.cpp b/src/osgEarthProcedural/VegetationLayer.cpp index 9790ee3b76..71e74438e5 100644 --- a/src/osgEarthProcedural/VegetationLayer.cpp +++ b/src/osgEarthProcedural/VegetationLayer.cpp @@ -210,7 +210,7 @@ VegetationLayer::Options::fromConfig(const Config& conf) groups()[GROUP_UNDERGROWTH].lod().setDefault(19); groups()[GROUP_UNDERGROWTH].enabled().setDefault(true); groups()[GROUP_UNDERGROWTH].castShadows().setDefault(false); - groups()[GROUP_UNDERGROWTH].maxRange().setDefault(FLT_MAX); + groups()[GROUP_UNDERGROWTH].maxRange().setDefault(FLT_MAX); groups()[GROUP_UNDERGROWTH].instancesPerSqKm().setDefault(500000); groups()[GROUP_UNDERGROWTH].overlap().setDefault(1.0f); groups()[GROUP_UNDERGROWTH].farLODScale().setDefault(2.0f); @@ -269,7 +269,7 @@ VegetationLayer::LayerAcceptor::acceptLayer( { // if this is a shadow camera and the layer is configured to cast shadows, accept it. if (CameraUtils::isShadowCamera(camera)) - { + { return _layer->getCastShadows(); } @@ -400,7 +400,7 @@ VegetationLayer::dirty() { _tiles.scoped_lock([this]() { - _tiles.clear(); + _tiles.clear(); _placeholders.clear(); }); @@ -473,7 +473,7 @@ VegetationLayer::setImpostorHighAngle(const Angle& value) getOrCreateStateSet()->getOrCreateUniform( "oe_veg_bbd1", osg::Uniform::FLOAT)->set( - clamp(1.0f-cosf(value.as(Units::RADIANS)), 0.0f, 1.0f)); + clamp(1.0f - cosf(value.as(Units::RADIANS)), 0.0f, 1.0f)); } const Angle& @@ -758,7 +758,7 @@ VegetationLayer::prepareForRendering(TerrainEngine* engine) if (res) { // Compute LOD for each asset group if necessary. - for(auto iter : options().groups()) + for (auto iter : options().groups()) { Options::Group& group = iter.second; if (group.lod() == 0) @@ -775,9 +775,9 @@ VegetationLayer::prepareForRendering(TerrainEngine* engine) } group.lod() = bestLOD; - OE_INFO << LC + OE_INFO << LC << "Rendering asset group" << iter.first - << " at terrain level " << bestLOD << std::endl; + << " at terrain level " << bestLOD << std::endl; } } } @@ -795,7 +795,7 @@ VegetationLayer::prepareForRendering(TerrainEngine* engine) ss->setMode(GL_CULL_FACE, 0x0 | osg::StateAttribute::PROTECTED); // Install the texture arena: - TextureArena* textures = getBiomeLayer()->getBiomeManager().getTextures(); + TextureArena* textures = getBiomeLayer()->getBiomeManager().getTextures(); ss->setAttribute(textures); // Apply a maximum GPU texture size @@ -834,7 +834,7 @@ namespace ImageLayer* layer, const std::string& sampler, const std::string& matrix, - osg::StateSet* stateset ) + osg::StateSet* stateset) { if (layer) { stateset->setDefine(sampler, layer->getSharedTextureUniformName()); @@ -888,7 +888,7 @@ VegetationLayer::configureImpostor( float ymin = xmin; float xmax = std::max(b.xMax(), b.yMax()); float ymax = xmax; - + const osg::Vec4f colors[1] = { {1,1,1,1} }; @@ -1082,7 +1082,7 @@ VegetationLayer::checkForNewAssets() const // next, foreach group, calculate the relative weighting by // inserting heavy instances more than once. - for(auto iter : instances_by_group) + for (auto iter : instances_by_group) { auto& group = iter.first; auto& instances = iter.second; @@ -1275,7 +1275,7 @@ VegetationLayer::getAssetPlacements( // to place vegetation std::vector constraints; _constraintQuery.getConstraints( - key, + key, constraints, progress); @@ -1516,7 +1516,7 @@ VegetationLayer::getAssetPlacements( double so = 1.0 - overlap; double a_min[2] = { local.x() + abb.xMin() * so, local.y() + abb.yMin() * so }; double a_max[2] = { local.x() + abb.xMax() * so, local.y() + abb.yMax() * so }; - + if (index.Search(a_min, a_max, nullptr) == 0) { index.Insert(a_min, a_max, 0); @@ -1531,7 +1531,7 @@ VegetationLayer::getAssetPlacements( // Generate a random rotation and record the position. // Do this before the constraint check to maintain determinism! float rotation = RAND() * 3.1415927 * 2.0; - + if (!inConstrainedRegion(map_point.x(), map_point.y(), constraints)) { map_points.emplace_back(map_point); @@ -1554,10 +1554,10 @@ VegetationLayer::getAssetPlacements( // lifemap changes don't change existing assets (due to the // collision rtree). int numResults = result.size(); - for(int i=0; i p.density()) { result[i] = std::move(result[numResults - 1]); @@ -1651,9 +1651,7 @@ VegetationLayer::createDrawable( } void -VegetationLayer::cull( - const TileBatch& batch, - osg::NodeVisitor& nv) const +VegetationLayer::cull(const TileBatch& batch, osg::NodeVisitor& nv) const { if (_assets.empty()) return; @@ -1862,18 +1860,5 @@ VegetationLayer::releaseGLObjects(osg::State* state) const { PatchLayer::releaseGLObjects(state); - ScopedMutexLock lock(_tiles); - - for (auto& tile : _tiles) - { - auto drawable = tile.second->_drawable.get(); - if (drawable.valid()) - drawable->releaseGLObjects(state); - } - - if (getBiomeLayer()) - { - auto textures = getBiomeLayer()->getBiomeManager().getTextures(); - textures->releaseGLObjects(state); - } + const_cast(this)->dirty(); }