| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- #ifndef ANKI_GL_TEXTURE_H
- #define ANKI_GL_TEXTURE_H
- #include "anki/util/Assert.h"
- #include "anki/util/Array.h"
- #include "anki/util/Singleton.h"
- #include "anki/util/Vector.h"
- #include "anki/util/StdTypes.h"
- #include "anki/util/NonCopyable.h"
- #include "anki/gl/Ogl.h"
- #include <cstdlib>
- #include <cstring>
- #include <limits>
- #include <thread>
- namespace anki {
- class Texture;
- /// @addtogroup OpenGL
- /// @{
- /// The absolute limit of textures
- const U MAX_TEXTURES = 512;
- /// Contains a few hints on how to crate textures
- class TextureManager
- {
- public:
- TextureManager();
- /// @name Accessors
- /// @{
- U getAnisotropyLevel() const
- {
- return anisotropyLevel;
- }
- void setAnisotropyLevel(U x)
- {
- anisotropyLevel = x;
- }
- Bool getMipmappingEnabled() const
- {
- return mipmapping;
- }
- void setMipmappingEnabled(Bool x)
- {
- mipmapping = x;
- }
- Bool getCompressionEnabled() const
- {
- return compression;
- }
- void setCompressionEnabled(Bool x)
- {
- compression = x;
- }
- U getMaxUnitsCount() const
- {
- return unitsCount;
- }
- /// @}
- private:
- /// @name Hints
- /// Hints when creating new textures. The implementation may try to ignore
- /// them
- /// @{
- U anisotropyLevel;
- Bool mipmapping;
- /// If true the new textures will be compressed if not already
- Bool compression;
- /// @}
- U unitsCount;
- };
- /// The global texture manager
- typedef Singleton<TextureManager> TextureManagerSingleton;
- /// Class for effective binding of textures
- ///
- /// @note GL has some nonsense where you can bind different texture targets in
- /// the same unit. This class doesn't support that
- class TextureUnits
- {
- public:
- TextureUnits();
- /// Alias for glActiveTexture
- void activateUnit(U unit);
- /// Bind the texture to a unit. It's not sure that it will activate the unit
- /// @return The texture unit index
- U bindTexture(const Texture& tex);
- /// Like bindTexture but ensure that the unit is active
- void bindTextureAndActivateUnit(const Texture& tex);
- /// Unbind a texture from it's unit
- void unbindTexture(const Texture& tex);
- /// Get the number of the texture unit the @a tex is binded. Returns -1 if
- /// not binded to any unit
- I whichUnit(const Texture& tex);
- private:
- /// Texture unit representation
- struct Unit
- {
- /// Have the GL ID to save memory. 0 if no tex is binded to that unit
- GLuint tex;
-
- /// Born time. The bigger the value the latter the unit has been
- /// accessed. This practically means that if the @a born is low the
- /// unit is a candidate for replacement
- U64 born;
- };
- /// Texture units
- Vector<Unit> units;
- /// A map that goes from a texture name to it's bound unit. We don't keep
- /// the unit in the texture because it could be different for each context
- Vector<I8> texIdToUnitId;
- /// The active texture unit
- I activeUnit;
- /// How many times the @a choseUnit has been called. Used to set the
- /// Unit::born
- U64 choseUnitTimes;
- /// Helper method. It returns the texture unit where the @a tex can be
- /// binded
- U choseUnit(const Texture& tex, Bool& allreadyBinded);
- };
- /// The global texture units manager. Its per thread
- typedef SingletonThreadSafe<TextureUnits> TextureUnitsSingleton;
- /// Texture class.
- /// Generally its thread safe as long as you have a shared context and the
- /// driver supports it
- class Texture: public NonCopyable
- {
- friend class TextureManager;
- public:
- // A fake enum: Texture filtering type
- typedef U8 TextureFilteringType;
- enum
- {
- TFT_NEAREST,
- TFT_LINEAR,
- TFT_TRILINEAR
- };
- /// Texture initializer struct
- struct Initializer
- {
- struct Data
- {
- const void* ptr;
- PtrSize size;
- };
- U width = 0;
- U height = 0;
- U depth = 0; ///< Relevant only for 3D and 2DArray textures
- GLenum target = GL_TEXTURE_2D;
- GLenum internalFormat = GL_NONE;
- GLenum format = GL_NONE;
- GLenum type = GL_NONE;
- U mipmapsCount = 0;
- TextureFilteringType filteringType = TFT_NEAREST;
- Bool repeat = false;
- I anisotropyLevel = 0;
- Bool genMipmaps = false;
- U samples = 1;
- Array<Array<Data, 128>, 128> data; ///< Array of data in: [mip][layer]
- Initializer()
- {
- memset(&data[0][0], 0, sizeof(data));
- }
- };
- /// @name Constructors/Destructor
- /// @{
- /// Default constructor
- Texture()
- {}
- Texture(const Initializer& init)
- {
- create(init);
- }
- /// Desrcuctor
- ~Texture();
- /// @}
- /// @name Accessors
- /// Thread safe
- /// @{
- GLuint getGlId() const
- {
- ANKI_ASSERT(isCreated());
- return glId;
- }
- GLenum getInternalFormat() const
- {
- ANKI_ASSERT(isCreated());
- return internalFormat;
- }
- GLenum getFormat() const
- {
- ANKI_ASSERT(isCreated());
- return format;
- }
- GLenum getTarget() const
- {
- ANKI_ASSERT(isCreated());
- return target;
- }
- GLenum getType() const
- {
- ANKI_ASSERT(isCreated());
- return type;
- }
- I getUnit() const
- {
- ANKI_ASSERT(isCreated());
- return TextureUnitsSingleton::get().whichUnit(*this);
- }
- GLuint getWidth() const
- {
- ANKI_ASSERT(isCreated());
- return width;
- }
- GLuint getHeight() const
- {
- ANKI_ASSERT(isCreated());
- return height;
- }
- GLuint getDepth() const
- {
- ANKI_ASSERT(isCreated());
- return depth;
- }
- /// @}
- /// Create a texture
- void create(const Initializer& init);
- /// Create a FAI
- void create2dFai(
- U w, U h, GLenum internalFormat, GLenum format, GLenum type,
- U samples = 1);
- /// Bind the texture to a unit that the texture unit system will decide
- /// @return The texture init
- U bind() const;
- /// Change the filtering type
- void setFiltering(const TextureFilteringType filterType)
- {
- TextureUnitsSingleton::get().bindTextureAndActivateUnit(*this);
- setFilteringNoBind(filterType);
- }
- TextureFilteringType getFiltering() const
- {
- return filtering;
- }
- /// Set texture parameter
- void setParameter(GLenum param, GLint value)
- {
- TextureUnitsSingleton::get().bindTextureAndActivateUnit(*this);
- glTexParameteri(target, param, value);
- }
- /// Read the data from the texture. Available only in GL desktop
- void readPixels(void* data, U level = 0) const;
- /// Set the range of the mipmaps
- /// @param baseLevel The level of the base mipmap. By default is 0
- /// @param maxLevel The level of the max mimap. Most of the time it's 1000.
- void setMipmapsRange(U baseLevel, U maxLevel);
- /// Generate mipmaps
- void generateMipmaps();
- private:
- GLuint glId = 0; ///< Identification for OGL
- GLenum target = GL_NONE; ///< GL_TEXTURE_2D, GL_TEXTURE_3D... etc
- GLenum internalFormat = GL_NONE; ///< GL_COMPRESSED_RED, GL_RGB16 etc
- GLenum format = GL_NONE; ///< GL_RED, GL_RG, GL_RGB etc
- GLenum type = GL_NONE; ///< GL_UNSIGNED_BYTE, GL_BYTE etc
- GLuint width = 0, height = 0, depth = 0;
- TextureFilteringType filtering;
- U8 samples = 1;
- Bool isCreated() const
- {
- return glId != 0;
- }
- void setFilteringNoBind(TextureFilteringType filterType);
- };
- /// @}
- } // end namespace anki
- #endif
|