Browse Source

Implemented ARB_texture_storage.

Equivalent functionality is in ES3 and also EXT_texture_storage ES2
extension.
pull/7/head
Vladimír Vondruš 14 years ago
parent
commit
f83c2b601b
  1. 69
      src/AbstractTexture.cpp
  2. 48
      src/AbstractTexture.h
  3. 15
      src/CubeMapTexture.h
  4. 24
      src/CubeMapTextureArray.h
  5. 58
      src/Texture.h

69
src/AbstractTexture.cpp

@ -33,6 +33,14 @@ AbstractTexture::ParameterfvImplementation AbstractTexture::parameterfvImplement
AbstractTexture::MipmapImplementation AbstractTexture::mipmapImplementation =
&AbstractTexture::mipmapImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
AbstractTexture::Storage1DImplementation AbstractTexture::storage1DImplementation =
&AbstractTexture::storageImplementationDefault;
#endif
AbstractTexture::Storage2DImplementation AbstractTexture::storage2DImplementation =
&AbstractTexture::storageImplementationDefault;
AbstractTexture::Storage3DImplementation AbstractTexture::storage3DImplementation =
&AbstractTexture::storageImplementationDefault;
#ifndef MAGNUM_TARGET_GLES
AbstractTexture::Image1DImplementation AbstractTexture::image1DImplementation =
&AbstractTexture::imageImplementationDefault;
#endif
@ -209,6 +217,9 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) {
parameterfImplementation = &AbstractTexture::parameterImplementationDSA;
parameterfvImplementation = &AbstractTexture::parameterImplementationDSA;
mipmapImplementation = &AbstractTexture::mipmapImplementationDSA;
storage1DImplementation = &AbstractTexture::storageImplementationDSA;
storage2DImplementation = &AbstractTexture::storageImplementationDSA;
storage3DImplementation = &AbstractTexture::storageImplementationDSA;
image1DImplementation = &AbstractTexture::imageImplementationDSA;
image2DImplementation = &AbstractTexture::imageImplementationDSA;
image3DImplementation = &AbstractTexture::imageImplementationDSA;
@ -258,6 +269,64 @@ void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLfloat
glTextureParameterfvEXT(_id, _target, parameter, values);
}
void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Math::Vector< 1, GLsizei >& size) {
bindInternal();
/** @todo Re-enable when extension wrangler is available for ES2 */
#ifndef MAGNUM_TARGET_GLES2
glTexStorage1D(target, levels, GLenum(internalFormat), size[0]);
#else
//glTexStorage2DEXT(target, levels, GLenum(internalFormat), size.x(), size.y());
static_cast<void>(target);
static_cast<void>(levels);
static_cast<void>(internalFormat);
static_cast<void>(size);
#endif
}
void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Math::Vector< 1, GLsizei >& size) {
glTextureStorage1DEXT(_id, target, levels, GLenum(internalFormat), size[0]);
}
#endif
void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector2i& size) {
bindInternal();
/** @todo Re-enable when extension wrangler is available for ES2 */
#ifndef MAGNUM_TARGET_GLES2
glTexStorage2D(target, levels, GLenum(internalFormat), size.x(), size.y());
#else
//glTexStorage2DEXT(target, levels, GLenum(internalFormat), size.x(), size.y());
static_cast<void>(target);
static_cast<void>(levels);
static_cast<void>(internalFormat);
static_cast<void>(size);
#endif
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector2i& size) {
glTextureStorage2DEXT(_id, target, levels, GLenum(internalFormat), size.x(), size.y());
}
#endif
void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector3i& size) {
bindInternal();
/** @todo Re-enable when extension wrangler is available for ES2 */
#ifndef MAGNUM_TARGET_GLES2
glTexStorage3D(target, levels, GLenum(internalFormat), size.x(), size.y(), size.z());
#else
//glTexStorage3DEXT(target, levels, GLenum(internalFormat), size.x(), size.y(), size.z());
static_cast<void>(target);
static_cast<void>(levels);
static_cast<void>(internalFormat);
static_cast<void>(size);
#endif
}
#ifndef MAGNUM_TARGET_GLES
void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, AbstractTexture::InternalFormat internalFormat, const Vector3i& size) {
glTextureStorage3DEXT(_id, target, levels, GLenum(internalFormat), size.x(), size.y(), size.z());
}
void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data) {
bindInternal();
glTexImage1D(target, level, static_cast<GLint>(internalFormat), size[0], 0, static_cast<GLenum>(format), static_cast<GLenum>(type), data);

48
src/AbstractTexture.h

@ -42,16 +42,17 @@ repeated @fn_gl{Get} calls.
If extension @extension{EXT,direct_state_access} is available, bind() uses DSA
function to avoid unnecessary calls to @fn_gl{ActiveTexture}. Also all texture
configuration functions use DSA functions to avoid unnecessary calls to
@fn_gl{ActiveTexture} and @fn_gl{BindTexture}. See respective function
documentation for more information.
configuration and data updating functions use DSA functions to avoid
unnecessary calls to @fn_gl{ActiveTexture} and @fn_gl{BindTexture}. See
respective function documentation for more information.
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.
Always fully configure the texture before setting the texture data, so OpenGL
can optimize the data to match your settings.
dedicated layers, not occupied by other textures. First configure the texture
and *then* set the data, so OpenGL can optimize them to match the settings. To
avoid redundant consistency checks and memory reallocations when updating
texture data, set texture storage at once using @ref Texture::setStorage() "setStorage()"
and then set data using @ref Texture::setSubImage() "setSubImage()".
You can use functions invalidateImage() and @ref Texture::invalidateSubImage() "invalidateSubImage()"
if you don't need texture data anymore to avoid unnecessary memory operations
@ -1187,6 +1188,27 @@ class MAGNUM_EXPORT AbstractTexture {
#endif
static MAGNUM_LOCAL MipmapImplementation mipmapImplementation;
#ifndef MAGNUM_TARGET_GLES
typedef void(AbstractTexture::*Storage1DImplementation)(GLenum, GLsizei, InternalFormat, const Math::Vector<1, GLsizei>&);
void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size);
void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size);
static Storage1DImplementation storage1DImplementation;
#endif
typedef void(AbstractTexture::*Storage2DImplementation)(GLenum, GLsizei, InternalFormat, const Vector2i&);
void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector2i& size);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector2i& size);
#endif
static Storage2DImplementation storage2DImplementation;
typedef void(AbstractTexture::*Storage3DImplementation)(GLenum, GLsizei, InternalFormat, const Vector3i&);
void MAGNUM_LOCAL storageImplementationDefault(GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector3i& size);
#ifndef MAGNUM_TARGET_GLES
void MAGNUM_LOCAL storageImplementationDSA(GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector3i& size);
#endif
static Storage3DImplementation storage3DImplementation;
#ifndef MAGNUM_TARGET_GLES
typedef void(AbstractTexture::*Image1DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector<1, GLsizei>&, AbstractImage::Format, AbstractImage::Type, const GLvoid*);
void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Format format, AbstractImage::Type type, const GLvoid* data);
@ -1262,6 +1284,10 @@ template<> struct AbstractTexture::DataHelper<1> {
(texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast<GLint>(wrapping.x()));
}
inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size) {
(texture->*storage1DImplementation)(target, levels, internalFormat, size);
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 1, void>::type set(AbstractTexture* texture, GLenum target, GLint level, InternalFormat internalFormat, Image* image) {
(texture->*image1DImplementation)(target, level, internalFormat, image->size(), image->format(), image->type(), image->data());
}
@ -1289,6 +1315,10 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> {
static void setWrapping(AbstractTexture* texture, const Array2D<Wrapping>& wrapping);
inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector2i& size) {
(texture->*storage2DImplementation)(target, levels, internalFormat, size);
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 2, void>::type set(AbstractTexture* texture, GLenum target, GLint level, InternalFormat internalFormat, Image* image) {
(texture->*image2DImplementation)(target, level, internalFormat, image->size(), image->format(), image->type(), image->data());
}
@ -1319,6 +1349,10 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> {
static void setWrapping(AbstractTexture* texture, const Array3D<Wrapping>& wrapping);
inline static void setStorage(AbstractTexture* texture, GLenum target, GLsizei levels, InternalFormat internalFormat, const Vector3i& size) {
(texture->*storage3DImplementation)(target, levels, internalFormat, size);
}
template<class Image> inline static typename std::enable_if<Image::Dimensions == 3, void>::type set(AbstractTexture* texture, GLenum target, GLint level, InternalFormat internalFormat, Image* image) {
(texture->*image3DImplementation)(target, level, internalFormat, image->size(), image->format(), image->type(), image->data());
}

15
src/CubeMapTexture.h

@ -51,8 +51,9 @@ Image2D positiveX({256, 256}, Image2D::Components::RGBA, Image2D::ComponentType:
CubeMapTexture texture;
texture.setMagnificationFilter(Texture2D::Filter::Linear)
// ...
->setImage(CubeMapTexture::Coordinate::PositiveX, 0, Texture2D::Format::RGBA8, &positiveX)
->setImage(CubeMapTexture::Coordinate::NegativeX, 0, Texture2D::Format::RGBA8, &negativeX)
->setStorage(Math::log2(256)+1, Texture2D::Format::RGBA8, {256, 256})
->setSubImage(CubeMapTexture::Coordinate::PositiveX, 0, {}, &positiveX)
->setSubImage(CubeMapTexture::Coordinate::NegativeX, 0, {}, &negativeX)
// ...
@endcode
@ -109,6 +110,16 @@ class CubeMapTexture: public AbstractTexture {
return this;
}
/**
* @brief Set storage
*
* See Texture::setStorage() for more information.
*/
inline CubeMapTexture* setStorage(GLsizei levels, InternalFormat internalFormat, const Vector2i& size) {
DataHelper<2>::setStorage(this, _target, levels, internalFormat, size);
return this;
}
/**
* @brief Set image data
* @param coordinate Coordinate

24
src/CubeMapTextureArray.h

@ -34,24 +34,24 @@ See CubeMapTexture documentation for introduction.
@section CubeMapTextureArray-usage Usage
Common usage is to specify each layer and face separately using setSubImage().
You have to allocate the memory for all layers and faces first, possibly by
passing properly sized empty Image to setImage(). Example: array with 16
layers of cube map faces, each face consisting of six 64x64 images:
You have to allocate the memory for all layers and faces first either by
calling setStorage() or by passing properly sized empty Image to setImage().
Example: array with 16 layers of cube map faces, each face consisting of six
64x64 images:
@code
Image3D dummy({64, 64, 16*6}, Image3D::Components::RGBA, Image3D::ComponentType::UnsignedByte, nullptr);
CubeMapTextureArray texture;
texture.setMagnificationFilter(CubeMapTextureArray::Filter::Linear)
// ...
->setImage(0, CubeMapTextureArray::Format::RGBA8, &dummy);
->setStorage(Math::log2(64)+1, CubeMapTextureArray::Format::RGBA8, {64, 64, 16});
for(std::size_t i = 0; i != 16; ++i) {
void* dataPositiveX = ...;
Image2D imagePositiveX({64, 64}, Image3D::Components::RGBA, Image3D::ComponentType::UnsignedByte, imagePositiveX);
// ...
texture->setSubImage(i, CubeMapTextureArray::Coordinate::PositiveX, 0, imagePositiveX);
texture->setSubImage(i, CubeMapTextureArray::Coordinate::NegativeX, 0, imageNegativeX);
texture->setSubImage(i, CubeMapTextureArray::Coordinate::PositiveX, 0, {}, imagePositiveX);
texture->setSubImage(i, CubeMapTextureArray::Coordinate::NegativeX, 0, {}, imageNegativeX);
// ...
}
@ -99,6 +99,16 @@ class CubeMapTextureArray: public AbstractTexture {
return this;
}
/**
* @brief Set storage
*
* See Texture::setStorage() for more information.
*/
inline CubeMapTextureArray* setStorage(GLsizei levels, InternalFormat internalFormat, const Vector3i& size) {
DataHelper<3>::setStorage(this, _target, levels, internalFormat, size);
return this;
}
/**
* @brief Set image data
* @param level Mip level

58
src/Texture.h

@ -44,17 +44,18 @@ texture.setMagnificationFilter(Texture2D::Filter::Linear)
->setMinificationFilter(Texture2D::Filter::Linear, Texture2D::Mipmap::Linear)
->setWrapping(Texture2D::Wrapping::ClampToEdge)
->setMaxAnisotropy(Texture2D::maxSupportedAnisotropy)
->setImage(0, Texture2D::Format::RGBA8, &image)
->setStorage(Math::log2(4096)+1, Texture2D::Format::RGBA8, {4096, 4096})
->setSubImage(0, {}, &image)
->generateMipmap();
@endcode
@attention Don't forget to fully configure the texture before use. Note that
default configuration (if setMinificationFilter() is not called with
another value) is to use mipmaps, so be sure to either call setMinificationFilter(),
explicitly set all mip levels or call generateMipmap(). If using rectangle
texture, you must also call setWrapping(), because the initial value is
not supported on rectangle textures. See also setMagnificationFilter() and
setBorderColor().
explicitly specify all mip levels with setStorage() and setImage() or call
generateMipmap(). If using rectangle texture, you must also call
setWrapping(), because the initial value is not supported on rectangle
textures. See also setMagnificationFilter() and setBorderColor().
The texture is bound to layer specified by shader via bind(). In shader, the
texture is used via `sampler1D`, `sampler2D` or `sampler3D` depending on
@ -67,16 +68,14 @@ You can create texture arrays by passing @ref Texture::Target "Texture2D::Target
or @ref Texture::Target "Texture3D::Target::Texture2DArray" to constructor.
It is possible to specify each layer separately using setSubImage(), but you
have to allocate the memory for all layers first, possibly by passing properly
sized empty Image to setImage(). Example: 2D texture array with 16 layers of
64x64 images:
have to allocate the memory for all layers first either by calling setStorage()
or by passing properly sized empty Image to setImage(). Example: 2D texture
array with 16 layers of 64x64 images:
@code
Image3D dummy({64, 64, 16}, Image3D::Components::RGBA, Image3D::ComponentType::UnsignedByte, nullptr);
Texture3D texture(Texture3D::Target::Texture2DArray);
texture.setMagnificationFilter(Texture2D::Filter::Linear)
// ...
->setImage(0, Texture2D::Format::RGBA8, &dummy);
->setStorage(levels, Texture2D::Format::RGBA8, {64, 64,16});
for(std::size_t i = 0; i != 16; ++i) {
void* data = ...;
@ -198,6 +197,33 @@ template<std::uint8_t dimensions> class Texture: public AbstractTexture {
return this;
}
/**
* @brief Set storage
* @param levels Mip level count
* @param internalFormat Internal format
* @param size Size of largest mip level
* @return Pointer to self (for method chaining)
*
* Specifies entire structure of a texture at once, removing the need
* for additional consistency checks and memory reallocations when
* updating the data later. After calling this function the texture
* is immutable and calling setStorage() or setImage() is not allowed.
*
* If @extension{EXT,direct_state_access} is not available, the
* texture is bound to some layer before the operation.
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and
* @fn_gl{TexStorage1D}/@fn_gl{TexStorage2D}/@fn_gl{TexStorage3D}
* or @fn_gl_extension{TextureStorage1D,EXT,direct_state_access}/
* @fn_gl_extension{TextureStorage2D,EXT,direct_state_access}/
* @fn_gl_extension{TextureStorage3D,EXT,direct_state_access}
* @requires_gl42 %Extension @extension{ARB,texture_storage}
* @requires_gles30 %Extension @es_extension{EXT,texture_storage}
*/
inline Texture<Dimensions>* setStorage(GLsizei levels, InternalFormat internalFormat, const typename DimensionTraits<Dimensions, GLint>::VectorType& size) {
DataHelper<Dimensions>::setStorage(this, _target, levels, internalFormat, size);
return this;
}
/**
* @brief Set image data
* @param level Mip level
@ -208,9 +234,13 @@ template<std::uint8_t dimensions> class Texture: public AbstractTexture {
*
* The image is not deleted afterwards.
*
* For better performance when generating mipmaps using
* generateMipmap() or calling setImage() more than once use
* setStorage() and setSubImage() instead.
*
* If @extension{EXT,direct_state_access} is not available, the
* texture is bound to some layer before the operation.
* @see setSubImage(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and
* @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and
* @fn_gl{TexImage1D}/@fn_gl{TexImage2D}/@fn_gl{TexImage3D} or
* @fn_gl_extension{TextureImage1D,EXT,direct_state_access}/
* @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/
@ -240,8 +270,8 @@ template<std::uint8_t dimensions> class Texture: public AbstractTexture {
*
* If @extension{EXT,direct_state_access} is not available, the
* texture is bound to some layer before the operation.
* @see setImage(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and
* @fn_gl{TexSubImage1D}/@fn_gl{TexSubImage2D}/@fn_gl{TexSubImage3D}
* @see setStorage(), setImage(), @fn_gl{ActiveTexture}, @fn_gl{BindTexture}
* and @fn_gl{TexSubImage1D}/@fn_gl{TexSubImage2D}/@fn_gl{TexSubImage3D}
* or @fn_gl_extension{TextureSubImage1D,EXT,direct_state_access}/
* @fn_gl_extension{TextureSubImage2D,EXT,direct_state_access}/
* @fn_gl_extension{TextureSubImage3D,EXT,direct_state_access}

Loading…
Cancel
Save