From 7b517d31ebb8b7e778275e352edaa88f33e393e6 Mon Sep 17 00:00:00 2001 From: Glenn Waldron Date: Tue, 26 Mar 2024 12:41:28 -0400 Subject: [PATCH] ChonkFactory default weak texture cache, TextureArena support for all wrapping dimensions --- src/osgEarth/Chonk | 32 ++++++++++++++++++++------------ src/osgEarth/Chonk.cpp | 23 ++++++++++++++++------- src/osgEarth/GLSLChunker.cpp | 11 ++++++++--- src/osgEarth/Metrics | 2 +- src/osgEarth/Registry.cpp | 2 -- src/osgEarth/TextureArena | 9 ++++----- src/osgEarth/TextureArena.cpp | 20 +++++++++++++++----- src/osgEarth/TiledModelLayer | 4 ++-- src/osgEarth/TiledModelLayer.cpp | 12 ++++-------- src/osgEarth/Utils.cpp | 28 ++++++++++++++-------------- 10 files changed, 84 insertions(+), 59 deletions(-) diff --git a/src/osgEarth/Chonk b/src/osgEarth/Chonk index 8a3bb42157..7343a4ccb3 100644 --- a/src/osgEarth/Chonk +++ b/src/osgEarth/Chonk @@ -63,7 +63,7 @@ namespace osgEarth private: //! hidden to force use of create() - ChonkMaterial() { } + ChonkMaterial() = default; }; class ChonkFactory; @@ -180,16 +180,22 @@ namespace osgEarth using GetOrCreateFunction = std::function; - osg::ref_ptr _textures; + //! Texture arena into which this factory will place textures it finds + osg::ref_ptr textures; - GetOrCreateFunction _getOrCreateTexture; + //! Texture caching function + GetOrCreateFunction getOrCreateTexture; public: - ChonkFactory( - TextureArena* textures); + //! Default, user should supply a TextureArena. + ChonkFactory(); - //! User function that can try to find textures instead of - //! creating new ones. Good for sharing data across invocations. + //! Construct with a texture arena. + ChonkFactory(TextureArena* textures); + + //! Function that can try to find textures instead of + //! creating new ones. Good for sharing data across invocations, and + //! for preventint duplicate textures in the arena. void setGetOrCreateFunction(GetOrCreateFunction); //! For the given node, this method populates the provided Chonk wit @@ -208,14 +214,16 @@ namespace osgEarth float far_pixel_scale, float near_pixel_scale); - /** - * Stock "getOrCreateTexture" function for the ChonkFactory that works on - * a vector of Weak pointers. Use this or provide your own or don't use - * one at all. - */ + //! Stock "getOrCreateTexture" function for the ChonkFactory that works on + //! a vector of Weak pointers. Use this or provide your own or don't use + //! one at all. static GetOrCreateFunction getWeakTextureCacheFunction( std::vector& cache, std::mutex& cache_mutex); + + private: + mutable std::vector _texcache; + mutable std::mutex _texcache_mutex; }; /** diff --git a/src/osgEarth/Chonk.cpp b/src/osgEarth/Chonk.cpp index c451162c81..d6de7437d2 100644 --- a/src/osgEarth/Chonk.cpp +++ b/src/osgEarth/Chonk.cpp @@ -122,7 +122,7 @@ namespace ChonkDrawable* _drawable = nullptr; // optional. float _far_pixel_scale = 0.0f; float _near_pixel_scale = MAX_NEAR_PIXEL_SCALE; - TextureArena* _textures; + TextureArena* _textures = nullptr; ChonkFactory::GetOrCreateFunction _getOrCreateTexture; std::list _materialCache; std::stack _materialStack; @@ -622,16 +622,21 @@ Chonk::getBound() return _box; } -ChonkFactory::ChonkFactory(TextureArena* textures) : - _textures(textures) +ChonkFactory::ChonkFactory() { - //nop + getOrCreateTexture = getWeakTextureCacheFunction(_texcache, _texcache_mutex); +} + +ChonkFactory::ChonkFactory(TextureArena* in_textures) +{ + textures = in_textures; + getOrCreateTexture = getWeakTextureCacheFunction(_texcache, _texcache_mutex); } void ChonkFactory::setGetOrCreateFunction(GetOrCreateFunction value) { - _getOrCreateTexture = value; + getOrCreateTexture = value; } bool @@ -639,6 +644,8 @@ ChonkFactory::load(osg::Node* node, Chonk* chonk, float far_pixel_scale, float n { OE_SOFT_ASSERT_AND_RETURN(node != nullptr, false); OE_SOFT_ASSERT_AND_RETURN(chonk != nullptr, false); + OE_SOFT_ASSERT_AND_RETURN(textures.valid(), false, "ChonkFactory requires a valid TextureArena"); + OE_PROFILING_ZONE; // convert all primitive sets to indexed primitives @@ -655,7 +662,7 @@ ChonkFactory::load(osg::Node* node, Chonk* chonk, float far_pixel_scale, float n unsigned offset = chonk->_ebo_store.size(); // rip geometry and textures into a new Asset object - Ripper ripper(chonk, nullptr, _textures.get(), _getOrCreateTexture, far_pixel_scale, near_pixel_scale); + Ripper ripper(chonk, nullptr, textures.get(), getOrCreateTexture, far_pixel_scale, near_pixel_scale); node->accept(ripper); // dirty its bounding box @@ -674,6 +681,8 @@ ChonkFactory::load(osg::Node* node, ChonkDrawable* drawable, float far_pixel_sca { OE_SOFT_ASSERT_AND_RETURN(node != nullptr, false); OE_SOFT_ASSERT_AND_RETURN(drawable != nullptr, false); + OE_SOFT_ASSERT_AND_RETURN(textures.valid(), false, "ChonkFactory requires a valid TextureArena"); + OE_PROFILING_ZONE; Chonk::Ptr chonk; @@ -688,7 +697,7 @@ ChonkFactory::load(osg::Node* node, ChonkDrawable* drawable, float far_pixel_sca chonk->_ebo_store.reserve(counter._numElements); } - Ripper ripper(chonk.get(), drawable, _textures.get(), _getOrCreateTexture, far_pixel_scale, near_pixel_scale); + Ripper ripper(chonk.get(), drawable, textures.get(), getOrCreateTexture, far_pixel_scale, near_pixel_scale); node->accept(ripper); if (chonk && !chonk->_ebo_store.empty()) diff --git a/src/osgEarth/GLSLChunker.cpp b/src/osgEarth/GLSLChunker.cpp index e507765c2b..c31f1c7592 100644 --- a/src/osgEarth/GLSLChunker.cpp +++ b/src/osgEarth/GLSLChunker.cpp @@ -16,8 +16,8 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ -#include -#include +#include "GLSLChunker" +#include "StringUtils" #include using namespace osgEarth; @@ -219,10 +219,15 @@ namespace if (pos > 0 && pos != temp.npos) temp = temp.substr(pos); + bool is_directive = (temp.size() > 0 && temp[0] == '#'); + if (temp.find('}') != temp.npos && prefix.size() >= 4) prefix.resize(prefix.size() - 4); - out << prefix << temp << "\n"; + if (is_directive) + out << temp << "\n"; + else + out << prefix << temp << "\n"; if (temp.find('{') != temp.npos) prefix += " "; diff --git a/src/osgEarth/Metrics b/src/osgEarth/Metrics index 143d8a09e7..1ec5ac7fb7 100644 --- a/src/osgEarth/Metrics +++ b/src/osgEarth/Metrics @@ -66,7 +66,7 @@ namespace osgEarth { #define TRACY_ENABLE #define TRACY_ON_DEMAND #define TRACY_DELAYED_INIT -#include +#include #define OE_PROFILING_ZONE ZoneNamed( ___tracy_scoped_zone, osgEarth::Util::Metrics::enabled() ) #define OE_PROFILING_ZONE_NAMED(functionName) ZoneNamedN(___tracy_scoped_zone, functionName, osgEarth::Util::Metrics::enabled()) diff --git a/src/osgEarth/Registry.cpp b/src/osgEarth/Registry.cpp index ec5159d62a..80c61962aa 100644 --- a/src/osgEarth/Registry.cpp +++ b/src/osgEarth/Registry.cpp @@ -177,8 +177,6 @@ Registry::Registry() : osgDB::Registry::instance()->addArchiveExtension( "kmz" ); osgDB::Registry::instance()->addArchiveExtension( "3tz"); osgDB::Registry::instance()->addFileExtensionAlias( "3tz", "zip" ); - //osgDB::Registry::instance()->addFileExtensionAlias( "kmz", "kml" ); - osgDB::Registry::instance()->addMimeTypeExtensionMapping( "application/vnd.google-earth.kml+xml", "kml" ); osgDB::Registry::instance()->addMimeTypeExtensionMapping( "application/vnd.google-earth.kml+xml; charset=utf8", "kml"); osgDB::Registry::instance()->addMimeTypeExtensionMapping( "application/vnd.google-earth.kmz", "kmz" ); diff --git a/src/osgEarth/TextureArena b/src/osgEarth/TextureArena index 252589fb74..7a51e55b9f 100644 --- a/src/osgEarth/TextureArena +++ b/src/osgEarth/TextureArena @@ -16,8 +16,7 @@ * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ -#ifndef OSGEARTH_TEXTURE_ARENA_H -#define OSGEARTH_TEXTURE_ARENA_H 1 +#pragma once #include #include @@ -85,7 +84,9 @@ namespace osgEarth OE_PROPERTY(std::string, category); OE_PROPERTY(bool, compress); OE_PROPERTY(bool, mipmap); - OE_PROPERTY(bool, clamp); + OE_PROPERTY(bool, clamp_s); + OE_PROPERTY(bool, clamp_t); + OE_PROPERTY(bool, clamp_r); OE_PROPERTY(bool, keepImage); OE_PROPERTY(unsigned, maxDim); @@ -228,5 +229,3 @@ namespace osgEarth void notifyOfTextureRelease(osg::State*) const; }; } - -#endif // OSGEARTH_TEXTURE_ARENA_H diff --git a/src/osgEarth/TextureArena.cpp b/src/osgEarth/TextureArena.cpp index ff1f956a8e..9f8b276826 100644 --- a/src/osgEarth/TextureArena.cpp +++ b/src/osgEarth/TextureArena.cpp @@ -80,7 +80,9 @@ Texture::Texture(GLenum target_) : _globjects(MAX_CONTEXTS), _compress(true), _mipmap(true), - _clamp(false), + _clamp_s(false), + _clamp_t(false), + _clamp_r(false), _keepImage(true), _maxDim(63356), _target(target_), @@ -123,10 +125,18 @@ Texture::Texture(osg::Texture* input) : input->getFilter(osg::Texture::MIN_FILTER) == osg::Texture::NEAREST_MIPMAP_LINEAR || input->getFilter(osg::Texture::MIN_FILTER) == osg::Texture::NEAREST_MIPMAP_NEAREST; - clamp() = + clamp_s() = input->getWrap(osg::Texture::WRAP_S) == osg::Texture::CLAMP || input->getWrap(osg::Texture::WRAP_S) == osg::Texture::CLAMP_TO_EDGE; + clamp_t() = + input->getWrap(osg::Texture::WRAP_T) == osg::Texture::CLAMP || + input->getWrap(osg::Texture::WRAP_T) == osg::Texture::CLAMP_TO_EDGE; + + clamp_r() = + input->getWrap(osg::Texture::WRAP_R) == osg::Texture::CLAMP || + input->getWrap(osg::Texture::WRAP_R) == osg::Texture::CLAMP_TO_EDGE; + maxAnisotropy() = input->getMaxAnisotropy(); @@ -281,9 +291,9 @@ Texture::compileGLObjects(osg::State& state) const 0, // border minFilter, magFilter, - clamp() ? GL_CLAMP_TO_EDGE : GL_REPEAT, - clamp() ? GL_CLAMP_TO_EDGE : GL_REPEAT, - clamp() ? GL_CLAMP_TO_EDGE : GL_REPEAT, + clamp_s() ? GL_CLAMP_TO_EDGE : GL_REPEAT, + clamp_t() ? GL_CLAMP_TO_EDGE : GL_REPEAT, + clamp_r() ? GL_CLAMP_TO_EDGE : GL_REPEAT, maxAnisotropy().getOrUse(4.0f)); gc._gltexture = GLTexture::create( diff --git a/src/osgEarth/TiledModelLayer b/src/osgEarth/TiledModelLayer index 156d8f2e11..7e9d9259e8 100644 --- a/src/osgEarth/TiledModelLayer +++ b/src/osgEarth/TiledModelLayer @@ -22,6 +22,7 @@ #include #include #include +#include #include namespace osgEarth @@ -100,8 +101,7 @@ namespace osgEarth // NVGL support: osg::ref_ptr _textures; - mutable std::vector _texturesCache; - mutable std::mutex _texturesCacheMutex; + mutable ChonkFactory _chonkFactory; private: osg::observer_ptr< const Map > _map; diff --git a/src/osgEarth/TiledModelLayer.cpp b/src/osgEarth/TiledModelLayer.cpp index 8b1a298e60..4f550ddc64 100644 --- a/src/osgEarth/TiledModelLayer.cpp +++ b/src/osgEarth/TiledModelLayer.cpp @@ -139,19 +139,13 @@ TiledModelLayer::createTile(const TileKey& key, ProgressCallback* progress) cons { auto xform = findTopMostNodeOfType(result.get()); - // Convert the geometry into chonks - ChonkFactory factory(_textures); - - factory.setGetOrCreateFunction( - ChonkFactory::getWeakTextureCacheFunction(_texturesCache, _texturesCacheMutex)); - osg::ref_ptr drawable = new ChonkDrawable(); if (xform) { for (unsigned i = 0; i < xform->getNumChildren(); ++i) { - drawable->add(xform->getChild(i), factory); + drawable->add(xform->getChild(i), _chonkFactory); } xform->removeChildren(0, xform->getNumChildren()); xform->addChild(drawable); @@ -159,7 +153,7 @@ TiledModelLayer::createTile(const TileKey& key, ProgressCallback* progress) cons } else { - if (drawable->add(result.get(), factory)) + if (drawable->add(result.get(), _chonkFactory)) { result = drawable; } @@ -194,6 +188,8 @@ TiledModelLayer::addedToMap(const Map* map) // auto release requires that we install this update callback! _textures->setAutoRelease(true); + _chonkFactory.textures = _textures; + getNode()->addUpdateCallback(new LambdaCallback<>([this](osg::NodeVisitor& nv) { _textures->update(nv); diff --git a/src/osgEarth/Utils.cpp b/src/osgEarth/Utils.cpp index 9e77c012cd..314dc4ec33 100644 --- a/src/osgEarth/Utils.cpp +++ b/src/osgEarth/Utils.cpp @@ -435,14 +435,14 @@ GeometryValidator::apply(osg::Geometry& geom) { if ( geom.getVertexArray() == 0L ) { - OE_NOTICE << LC << "NULL vertex array!!" << std::endl; + OE_WARN << LC << "NULL vertex array!!" << std::endl; return; } unsigned numVerts = geom.getVertexArray()->getNumElements(); if ( numVerts == 0 ) { - OE_NOTICE << LC << "No verts!! name=" << geom.getName() << std::endl; + OE_WARN << LC << "No verts!! name=" << geom.getName() << std::endl; return; } @@ -458,25 +458,25 @@ GeometryValidator::apply(osg::Geometry& geom) { if ( a->getBinding() == a->BIND_OVERALL && a->getNumElements() != 1 ) { - OE_NOTICE << LC << "Found an array with BIND_OVERALL and size <> 1" << std::endl; + OE_WARN << LC << "Found an array with BIND_OVERALL and size <> 1" << std::endl; } else if ( a->getBinding() == a->BIND_PER_VERTEX && a->getNumElements() != numVerts ) { - OE_NOTICE << LC << a->className () << " : Found BIND_PER_VERTEX with wrong number of elements (expecting " << numVerts << "; found " << a->getNumElements() << ")" << std::endl; + OE_WARN << LC << a->className () << " : Found BIND_PER_VERTEX with wrong number of elements (expecting " << numVerts << "; found " << a->getNumElements() << ")" << std::endl; } _vbos.insert( a->getVertexBufferObject() ); } else { - OE_NOTICE << LC << "Found a NULL array" << std::endl; + OE_WARN << LC << "Found a NULL array" << std::endl; } } if ( _vbos.size() != 1 ) { - OE_NOTICE << LC << "Found a Geometry that uses more than one VBO (non-optimal sharing)" << std::endl; + OE_WARN << LC << "Found a Geometry that uses more than one VBO (non-optimal sharing)" << std::endl; } const osg::Geometry::PrimitiveSetList& plist = geom.getPrimitiveSetList(); @@ -492,15 +492,15 @@ GeometryValidator::apply(osg::Geometry& geom) { if ( da->getFirst() >= (GLint)numVerts ) { - OE_NOTICE << LC << "DrawArrays: first > numVerts" << std::endl; + OE_WARN << LC << "DrawArrays: first > numVerts" << std::endl; } if ( da->getFirst()+da->getCount() > (GLint)numVerts ) { - OE_NOTICE << LC << "DrawArrays: first/count out of bounds" << std::endl; + OE_WARN << LC << "DrawArrays: first/count out of bounds" << std::endl; } if ( da->getCount() < 1 ) { - OE_NOTICE << LC << "DrawArrays: count is zero" << std::endl; + OE_WARN << LC << "DrawArrays: count is zero" << std::endl; } } @@ -529,25 +529,25 @@ GeometryValidator::apply(osg::Geometry& geom) if ( pset->getNumIndices() == 0 ) { - OE_NOTICE << LC << "Primset: num elements = 0; class=" << pset->className() << ", name=" << pset->getName() << "" << std::endl; + OE_WARN << LC << "Primset: num elements = 0; class=" << pset->className() << ", name=" << pset->getName() << "" << std::endl; } else if ( pset->getType() >= GL_TRIANGLES && pset->getNumIndices() < 3 ) { - OE_NOTICE << LC << "Primset: not enough indicies for surface prim type" << std::endl; + OE_WARN << LC << "Primset: not enough indicies for surface prim type" << std::endl; } else if ( pset->getType() >= GL_LINE_STRIP && pset->getNumIndices() < 2 ) { - OE_NOTICE << LC << "Primset: not enough indicies for linear prim type" << std::endl; + OE_WARN << LC << "Primset: not enough indicies for linear prim type" << std::endl; } else if ( isDe && pset->getType() == GL_LINES && pset->getNumIndices() % 2 != 0 ) { - OE_NOTICE << LC << "Primset: non-even index count for GL_LINES" << std::endl; + OE_WARN << LC << "Primset: non-even index count for GL_LINES" << std::endl; } } if ( _ebos.size() != 1 ) { - OE_NOTICE << LC << "Found a Geometry that uses more than one EBO (non-optimal sharing)" << std::endl; + OE_WARN << LC << "Found a Geometry that uses more than one EBO (non-optimal sharing)" << std::endl; } }