Browse Source

Tracking texture state - bindings and limits.

vectorfields
Vladimír Vondruš 14 years ago
parent
commit
f9099a86bf
  1. 68
      src/AbstractTexture.cpp
  2. 53
      src/AbstractTexture.h
  3. 2
      src/BufferedTexture.h
  4. 2
      src/Context.cpp
  5. 6
      src/CubeMapTexture.h
  6. 8
      src/CubeMapTextureArray.h
  7. 4
      src/Implementation/State.cpp
  8. 2
      src/Implementation/State.h
  9. 36
      src/Implementation/TextureState.h
  10. 6
      src/Texture.h

68
src/AbstractTexture.cpp

@ -15,6 +15,10 @@
#include "AbstractTexture.h"
#include "Context.h"
#include "Implementation/State.h"
#include "Implementation/TextureState.h"
namespace Magnum {
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -35,25 +39,49 @@ static_assert((filter_or(NearestNeighbor, BaseLevel) == GL_NEAREST) &&
#endif
GLint AbstractTexture::maxSupportedLayerCount() {
GLint value;
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &value);
return value;
return Context::current()->state()->texture->maxSupportedLayerCount;
}
#ifndef MAGNUM_TARGET_GLES
GLfloat AbstractTexture::maxSupportedAnisotropy() {
GLfloat value;
GLfloat& value = Context::current()->state()->texture->maxSupportedAnisotropy;
/* Get the value, if not already cached */
if(value == 0.0f)
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &value);
return value;
}
#endif
AbstractTexture::~AbstractTexture() {
/* Remove all bindings */
for(GLuint& binding: Context::current()->state()->texture->bindings)
if(binding == _id) binding = 0;
glDeleteTextures(1, &_id);
}
void AbstractTexture::bind(GLint layer) {
Implementation::TextureState* const textureState = Context::current()->state()->texture;
/* If already bound in given layer, nothing to do */
if(textureState->bindings[layer] == _id) return;
/* Change to given layer, if not already there */
if(textureState->currentLayer != layer)
glActiveTexture(GL_TEXTURE0 + (textureState->currentLayer = layer));
/* Bind the texture to the layer */
glBindTexture(_target, (textureState->bindings[layer] = _id));
}
AbstractTexture* AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) {
#ifndef MAGNUM_TARGET_GLES
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Mipmap::BaseLevel, "AbstractTexture: rectangle textures cannot have mipmaps", this);
#endif
bind();
bindInternal();
glTexParameteri(_target, GL_TEXTURE_MIN_FILTER,
static_cast<GLint>(filter)|static_cast<GLint>(mipmap));
return this;
@ -64,11 +92,39 @@ AbstractTexture* AbstractTexture::generateMipmap() {
CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE, "AbstractTexture: rectangle textures cannot have mipmaps", this);
#endif
bind();
bindInternal();
glGenerateMipmap(_target);
return this;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
void AbstractTexture::bindInternal() {
Implementation::TextureState* const textureState = Context::current()->state()->texture;
/* If the texture is already bound in current layer, nothing to do */
if(textureState->bindings[textureState->currentLayer] == _id)
return;
/* Set internal layer as active if not already */
const GLint internalLayer = textureState->maxSupportedLayerCount-1;
if(textureState->currentLayer != internalLayer)
glActiveTexture(GL_TEXTURE0 + (textureState->currentLayer = internalLayer));
/* Bind the texture to internal layer, if not already */
if(textureState->bindings[internalLayer] != _id)
glBindTexture(_target, (textureState->bindings[internalLayer] = _id));
}
#endif
void AbstractTexture::initializeContextBasedFunctionality(Context* context) {
Implementation::TextureState* const textureState = context->state()->texture;
GLint& value = textureState->maxSupportedLayerCount;
/* Get the value and resize bindings array */
glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &value);
textureState->bindings.resize(value);
}
AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components components, AbstractTexture::ComponentType type) {
#ifndef MAGNUM_TARGET_GLES
#define internalFormatSwitch(c) switch(type) { \

53
src/AbstractTexture.h

@ -26,6 +26,8 @@
namespace Magnum {
class Context;
/**
@brief Base for textures
@ -42,10 +44,24 @@ AbstractShaderProgram::setUniform(GLint, GLint).
See Texture, CubeMapTexture and CubeMapTextureArray documentation for more
information.
@section AbstractTexture-performance-optimization Performance optimizations
The engine tracks currently bound textures in all available layers to avoid
unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}. %Texture
configuration functions use dedicated highest available texture layer to not
affect active bindings in user layers. %Texture limits (such as
maxSupportedLayerCount()) are cached, so repeated queries don't result in
repeated @fn_gl{Get} calls.
To achieve least state changes, fully configure each texture in one run --
method chaining comes in handy -- and try to have often used textures in
dedicated layers, not occupied by other textures.
@todo Add glPixelStore encapsulation
@todo Texture copying
*/
class MAGNUM_EXPORT AbstractTexture {
friend class Context;
AbstractTexture(const AbstractTexture& other) = delete;
AbstractTexture(AbstractTexture&& other) = delete;
AbstractTexture& operator=(const AbstractTexture& other) = delete;
@ -533,8 +549,8 @@ class MAGNUM_EXPORT AbstractTexture {
/**
* @brief Max supported layer count
*
* At least 48.
* @see bind(GLint), @fn_gl{Get} with @def_gl{MAX_COMBINED_TEXTURE_IMAGE_UNITS}
* @see bind(GLint), @fn_gl{Get} with @def_gl{MAX_COMBINED_TEXTURE_IMAGE_UNITS},
* @fn_gl{ActiveTexture}
*/
static GLint maxSupportedLayerCount();
@ -577,12 +593,9 @@ class MAGNUM_EXPORT AbstractTexture {
* Sets current texture as active in given layer. The layer must be
* between 0 and maxSupportedLayerCount(). Note that only one texture
* can be bound to given layer.
* @see bind(), @fn_gl{ActiveTexture}
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture}
*/
inline void bind(GLint layer) {
glActiveTexture(GL_TEXTURE0 + layer);
bind();
}
void bind(GLint layer);
/**
* @brief Set minification filter
@ -612,7 +625,7 @@ class MAGNUM_EXPORT AbstractTexture {
* @see bind(), @fn_gl{TexParameter} with @def_gl{TEXTURE_MAG_FILTER}
*/
inline AbstractTexture* setMagnificationFilter(Filter filter) {
bind();
bindInternal();
glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, static_cast<GLint>(filter));
return this;
}
@ -628,7 +641,7 @@ class MAGNUM_EXPORT AbstractTexture {
* @requires_gl
*/
inline AbstractTexture* setBorderColor(const Color4<GLfloat>& color) {
bind();
bindInternal();
glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, color.data());
return this;
}
@ -644,7 +657,7 @@ class MAGNUM_EXPORT AbstractTexture {
* @requires_extension @extension{EXT,texture_filter_anisotropic}
*/
inline AbstractTexture* setMaxAnisotropy(GLfloat anisotropy) {
bind();
bindInternal();
glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
return this;
}
@ -663,27 +676,19 @@ class MAGNUM_EXPORT AbstractTexture {
protected:
#ifndef DOXYGEN_GENERATING_OUTPUT
template<std::uint8_t textureDimensions> struct DataHelper {};
#endif
const GLenum _target; /**< @brief Target */
/* Unlike bind() this also sets the binding layer as active */
void bindInternal();
/**
* @brief Bind texture for parameter modification
*
* Unlike bind(GLint) doesn't bind the texture to any particular
* layer, thus unusable for binding for rendering.
* @see @fn_gl{BindTexture}
*/
inline void bind() {
glBindTexture(_target, _id);
}
const GLenum _target;
#endif
private:
static void initializeContextBasedFunctionality(Context* context);
GLuint _id;
};
inline AbstractTexture::~AbstractTexture() { glDeleteTextures(1, &_id); }
/** @relates AbstractTexture
@brief Convertor of component count and data type to InternalFormat

2
src/BufferedTexture.h

@ -133,7 +133,7 @@ class BufferedTexture: private AbstractTexture {
* @see @fn_gl{BindTexture}, @fn_gl{TexBuffer}
*/
void setBuffer(InternalFormat internalFormat, Buffer* buffer) {
AbstractTexture::bind();
bindInternal();
glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, buffer->id());
}
};

2
src/Context.cpp

@ -20,6 +20,7 @@
#include <Utility/Debug.h>
#include "AbstractShaderProgram.h"
#include "AbstractTexture.h"
#include "Buffer.h"
#include "Extensions.h"
#include "Implementation/State.h"
@ -201,6 +202,7 @@ Context::Context() {
/* Initialize functionality based on current OpenGL version and extensions */
AbstractShaderProgram::initializeContextBasedFunctionality(this);
Buffer::initializeContextBasedFunctionality(this);
AbstractTexture::initializeContextBasedFunctionality(this);
}
Context::~Context() {

6
src/CubeMapTexture.h

@ -86,7 +86,7 @@ class CubeMapTexture: public AbstractTexture {
* @copydoc Texture::setWrapping()
*/
inline CubeMapTexture* setWrapping(const Math::Vector<3, Wrapping>& wrapping) {
bind();
bindInternal();
DataHelper<3>::setWrapping(GL_TEXTURE_CUBE_MAP, wrapping);
return this;
}
@ -97,7 +97,7 @@ class CubeMapTexture: public AbstractTexture {
* @return Pointer to self (for method chaining)
*/
template<class Image> inline CubeMapTexture* setData(Coordinate coordinate, GLint mipLevel, InternalFormat internalFormat, Image* image) {
bind();
bindInternal();
DataHelper<2>::set(static_cast<GLenum>(coordinate), mipLevel, internalFormat, image);
return this;
}
@ -108,7 +108,7 @@ class CubeMapTexture: public AbstractTexture {
* @return Pointer to self (for method chaining)
*/
template<class Image> inline CubeMapTexture* setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector<2, GLint>& offset, const Image* image) {
bind();
bindInternal();
DataHelper<2>::setSub(static_cast<GLenum>(coordinate), mipLevel, offset, image);
return this;
}

8
src/CubeMapTextureArray.h

@ -60,7 +60,7 @@ class CubeMapTextureArray: public AbstractTexture {
* @copydoc Texture::setWrapping()
*/
inline CubeMapTextureArray* setWrapping(const Math::Vector<3, Wrapping>& wrapping) {
bind();
bindInternal();
DataHelper<3>::setWrapping(GL_TEXTURE_CUBE_MAP_ARRAY, wrapping);
return this;
}
@ -73,7 +73,7 @@ class CubeMapTextureArray: public AbstractTexture {
* The images are ordered the same way as Coordinate enum.
*/
template<class T> inline CubeMapTextureArray* setData(GLint mipLevel, InternalFormat internalFormat, T* image) {
bind();
bindInternal();
DataHelper<3>::set(GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, internalFormat, image);
return this;
}
@ -97,7 +97,7 @@ class CubeMapTextureArray: public AbstractTexture {
* @see setSubData(GLsizei, Coordinate, GLint, const Math::Vector<2, GLint>&, const Image*)
*/
template<class Image> inline CubeMapTextureArray* setSubData(GLint mipLevel, const Math::Vector<3, GLint>& offset, const Image* image) {
bind();
bindInternal();
DataHelper<3>::setSub(GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, offset, image, Math::Vector<3, GLsizei>(Math::Vector<Image::Dimensions, GLsizei>()));
return this;
}
@ -118,7 +118,7 @@ class CubeMapTextureArray: public AbstractTexture {
* @see setSubData(GLint, const Math::Vector<3, GLint>&, const Image*)
*/
template<class Image> inline CubeMapTextureArray* setSubData(GLsizei layer, Coordinate coordinate, GLint mipLevel, const Math::Vector<2, GLint>& offset, const Image* image) {
bind();
bindInternal();
DataHelper<3>::setSub(GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, Math::Vector<3, GLint>(offset, layer*6+static_cast<GLsizei>(coordinate)), image, Math::Vector<2, GLsizei>(Math::Vector<Image::Dimensions, GLsizei>()));
return this;
}

4
src/Implementation/State.cpp

@ -17,12 +17,14 @@
#include "BufferState.h"
#include "ShaderProgramState.h"
#include "TextureState.h"
namespace Magnum { namespace Implementation {
State::State(): buffer(new BufferState), shaderProgram(new ShaderProgramState) {}
State::State(): buffer(new BufferState), shaderProgram(new ShaderProgramState), texture(new TextureState) {}
State::~State() {
delete texture;
delete shaderProgram;
delete buffer;
}

2
src/Implementation/State.h

@ -21,6 +21,7 @@ namespace Magnum { namespace Implementation {
struct BufferState;
struct ShaderProgramState;
struct TextureState;
struct State {
State();
@ -28,6 +29,7 @@ struct State {
BufferState* const buffer;
ShaderProgramState* const shaderProgram;
TextureState* const texture;
};
}}

36
src/Implementation/TextureState.h

@ -0,0 +1,36 @@
#ifndef Magnum_Implementation_TextureState_h
#define Magnum_Implementation_TextureState_h
/*
Copyright © 2010, 2011, 2012 Vladimír Vondruš <mosra@centrum.cz>
This file is part of Magnum.
Magnum is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License version 3
only, as published by the Free Software Foundation.
Magnum 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 version 3 for more details.
*/
#include "Magnum.h"
#include "Buffer.h"
namespace Magnum { namespace Implementation {
struct TextureState {
inline TextureState(): maxSupportedLayerCount(0), maxSupportedAnisotropy(0.0f), currentLayer(0) {}
GLint maxSupportedLayerCount;
GLfloat maxSupportedAnisotropy;
GLint currentLayer;
std::vector<GLuint> bindings;
};
}}
#endif

6
src/Texture.h

@ -130,7 +130,7 @@ template<std::uint8_t dimensions> class Texture: public AbstractTexture {
* that can easily create all values the same)
*/
inline Texture<Dimensions>* setWrapping(const Math::Vector<Dimensions, Wrapping>& wrapping) {
bind();
bindInternal();
DataHelper<Dimensions>::setWrapping(_target, wrapping);
return this;
}
@ -148,7 +148,7 @@ template<std::uint8_t dimensions> class Texture: public AbstractTexture {
* @see bind(), @fn_gl{TexImage1D}, @fn_gl{TexImage2D}, @fn_gl{TexImage3D}
*/
template<class Image> inline Texture<Dimensions>* setData(GLint mipLevel, InternalFormat internalFormat, Image* image) {
bind();
bindInternal();
DataHelper<Dimensions>::set(_target, mipLevel, internalFormat, image);
return this;
}
@ -172,7 +172,7 @@ template<std::uint8_t dimensions> class Texture: public AbstractTexture {
* @see bind(), @fn_gl{TexSubImage1D}, @fn_gl{TexSubImage2D}, @fn_gl{TexSubImage3D}
*/
template<class Image> inline Texture<Dimensions>* setSubData(GLint mipLevel, const typename DimensionTraits<Dimensions, GLint>::VectorType& offset, Image* image) {
bind();
bindInternal();
DataHelper<Dimensions>::setSub(_target, mipLevel, offset, image);
return this;
}

Loading…
Cancel
Save