DYT/Tool/OpenSceneGraph-3.6.5/include/osgEarth/TextureArena

232 lines
8.0 KiB
Plaintext
Raw Permalink Normal View History

2024-12-24 23:49:36 +00:00
/* -*-c++-*- */
/* osgEarth - Geospatial SDK for OpenSceneGraph
* Copyright 2020 Pelican Mapping
* http://osgearth.org
*
* osgEarth is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#pragma once
#include <osgEarth/Common>
#include <osgEarth/GLUtils>
#include <osgEarth/URI>
#include <osg/Object>
#include <osg/StateAttribute>
#include <osg/buffered_value>
#include <osg/Image>
#include <queue>
#include <atomic>
namespace osgEarth
{
/**
* A texture that can be GPU-resident or not. Managed by a TextureArena.
*
* Stages of residency:
* 1. Not resident - only the URI is set
* 2. CPU resident - osg::Image is loaded into memory
* 3. GPU resident - GPU handle is in GPU table; GPU memory might not be allocated
* 4. GPU commited - GPU handle active, GPU texture fully available
*/
class OSGEARTH_EXPORT Texture
{
public:
using Ptr = std::shared_ptr<Texture>;
using WeakPtr = std::weak_ptr<Texture>;
//! Create for a given texture target
static Ptr create(
osg::Image* image = nullptr,
GLenum target = GL_TEXTURE_2D);
//! Create from an existing OSG texture instance
static Ptr create(
osg::Texture* tex);
//! Make this texture resident as a bindless texture
void makeResident(const osg::State&, bool toggle) const;
//! True if the texture is resident in state's context
bool isResident(const osg::State&) const;
//! True if the texture has been uploaded to the GPU
//! in the state's context
bool isCompiled(const osg::State&) const;
//! Whether we need to compile (or recompile) this texture
bool needsCompile(const osg::State&) const;
//! Wether the underlying image is dynamic
//! and needs updates.
bool needsUpdates() const;
//! Update the underlying image if necessary
void update(osg::NodeVisitor& nv);
//! GL memory functions
//! Returns true if the object needed compiling and was compiled.
bool compileGLObjects(osg::State&) const;
void resizeGLObjectBuffers(unsigned);
void releaseGLObjects(osg::State*, bool force = false) const;
OE_PROPERTY(std::string, name, {});
OE_PROPERTY(std::string, category, {});
OE_PROPERTY(bool, compress, true);
OE_PROPERTY(bool, mipmap, true);
OE_PROPERTY(bool, clamp_s, false);
OE_PROPERTY(bool, clamp_t, false);
OE_PROPERTY(bool, clamp_r, false);
OE_PROPERTY(bool, keepImage, true);
OE_PROPERTY(unsigned, maxDim, 65536);
OE_OPTION(URI, uri);
OE_OPTION(GLenum, internalFormat);
OE_OPTION(float, maxAnisotropy);
OE_PROPERTY(osg::ref_ptr<osg::Texture>, osgTexture, {});
OE_PROPERTY_CONST(GLenum, target, GL_TEXTURE_2D);
//! Whether any actual image data has been loaded into this object,
//! or whether we need to load it from the URI
bool dataLoaded() const;
//! GLObjects are shareable across GCs because they are static and bindless.
struct GLObjects : public BindlessShareableGLObjects
{
GLTexture::Ptr _gltexture;
unsigned _imageModCount = 0u;
};
mutable osg::buffered_object<GLObjects> _globjects;
~Texture();
protected:
Texture(GLenum target);
Texture(osg::Texture*);
void* _host;
friend class TextureArena;
};
typedef std::vector<Texture::Ptr> TextureVector;
/**
* TextureArena is a dynamic bindless texture atlas. Add as many texture
* as you want and control memory management by activating and deactivating
* them.
*
* Call add() to have the arena start managing a Texture.
* 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)
class OSGEARTH_EXPORT TextureArena : public osg::StateAttribute
{
public:
META_StateAttribute(osgEarth, TextureArena, OE_TEXTURE_ARENA_SA_TYPE_ID);
//! Construct an empty arena.
TextureArena();
//! Whether to automatically release textures when they are no longer
//! referenced anywhere outside of this arena. Default is false.
//! You can enable this if you want to populate the arena with
//! textures that will be released when their owners desctruct (for example).
void setAutoRelease(bool value);
bool getAutoRelease() const { return _autoRelease; }
//! Sets the GLSL binding point for the arena. Default is 1.
void setBindingPoint(unsigned value);
//! Sets the maximum texture size (in one dimension, in pixels)
//! to allocate on the GPU.
void setMaxTextureSize(unsigned pixels);
//! Adds a texture to the arena. On next apply() GL handles will allocate.
//! You only need to call this once for each texture.
//! Returns the index of the texture handle
int add(
Texture::Ptr tex,
const osgDB::Options* readOptions = nullptr);
//! Find and return the index of this texture in the arena,
//! or return -1 if not found.
int find(Texture::Ptr tex) const;
//! Find the texture at index i.
Texture::Ptr find(unsigned index) const;
//! Number of textures registered
size_t size() const { return _textures.size(); }
//! Textures installed in this arena
const TextureVector& getTextures() const { return _textures; }
//! destruct
virtual ~TextureArena();
//! Update traversal (called automatically if this TexturArena
//! is installed in a StateSet in the traversed scene graph)
void update(osg::NodeVisitor& nv);
//! Flush any unused textures immediately from the arena
void flush();
public: // StateAttribute
void apply(osg::State&) const override;
void compileGLObjects(osg::State&) const override;
void resizeGLObjectBuffers(unsigned) override;
void releaseGLObjects(osg::State*) const override;
int compare(const osg::StateAttribute& rhs) const override { return -1; }
private:
//! disable copy
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
{
bool _inUse = false;
bool _handleBufferDirty = true;
int _lastAppliedFrame = -1;
std::queue<int> _toCompile;
TextureVector _toRemove;
GLBuffer::Ptr _handleBuffer;
std::vector<GLuint64> _handles;
};
mutable osg::buffered_object<GLObjects> _globjects;
mutable TextureVector _textures;
mutable std::unordered_map<Texture*, unsigned> _textureIndices;
mutable std::unordered_set<unsigned> _dynamicTextures;
bool _autoRelease = false;
unsigned _bindingPoint = 1u;
bool _useUBO = false;
mutable int _releasePtr = 0;
unsigned _maxDim = 65536u;
mutable Mutex _m;
int find_no_lock(Texture::Ptr tex) const;
void purgeTextureIfOrphaned_no_lock(unsigned index);
friend class Texture;
void notifyOfTextureRelease(osg::State*) const;
};
}