232 lines
8.0 KiB
Plaintext
232 lines
8.0 KiB
Plaintext
|
/* -*-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;
|
||
|
};
|
||
|
}
|