diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index ed585c8ab..96444d692 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -245,6 +245,7 @@ supported. @es_extension{ANGLE,framebuffer_multisample} | done @es_extension{ANGLE,depth_texture} | done @es_extension{APPLE,framebuffer_multisample} | done (ES 3.0 subset) +@es_extension{APPLE,texture_max_level} | done @es_extension{ARM,rgba8} | done @es_extension{EXT,texture_type_2_10_10_10_REV} | done @es_extension{EXT,discard_framebuffer} | done diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index 427f90140..5766ae09f 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -146,6 +146,22 @@ void AbstractTexture::bindImplementationDSA(GLint textureUnit) { } #endif +#ifndef MAGNUM_TARGET_GLES2 +void AbstractTexture::setBaseLevel(Int level) { + (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_BASE_LEVEL, level); +} +#endif + +void AbstractTexture::setMaxLevel(Int level) { + (this->*Context::current()->state().texture->parameteriImplementation)( + #ifndef MAGNUM_TARGET_GLES2 + GL_TEXTURE_MAX_LEVEL + #else + GL_TEXTURE_MAX_LEVEL_APPLE + #endif + , level); +} + void AbstractTexture::setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap) { (this->*Context::current()->state().texture->parameteriImplementation)(GL_TEXTURE_MIN_FILTER, GLint(filter)|GLint(mipmap)); } diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index d0ab656f1..6b57cace1 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -242,6 +242,10 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { /* Unlike bind() this also sets the texture binding unit as active */ void MAGNUM_LOCAL bindInternal(); + #ifndef MAGNUM_TARGET_GLES2 + void setBaseLevel(Int level); + #endif + void setMaxLevel(Int level); void setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap); void setMagnificationFilter(Sampler::Filter filter); void setBorderColor(const Color4& color); diff --git a/src/Magnum/Context.cpp b/src/Magnum/Context.cpp index 5f28b479f..2c5e16127 100644 --- a/src/Magnum/Context.cpp +++ b/src/Magnum/Context.cpp @@ -214,6 +214,7 @@ const std::vector& Extension::extensions(Version version) { _extension(GL,ANGLE,framebuffer_multisample), _extension(GL,ANGLE,depth_texture), _extension(GL,APPLE,framebuffer_multisample), + _extension(GL,APPLE,texture_max_level), _extension(GL,ARM,rgba8), _extension(GL,EXT,texture_type_2_10_10_10_REV), _extension(GL,EXT,discard_framebuffer), diff --git a/src/Magnum/CubeMapTexture.h b/src/Magnum/CubeMapTexture.h index d750fd99d..53948a598 100644 --- a/src/Magnum/CubeMapTexture.h +++ b/src/Magnum/CubeMapTexture.h @@ -98,6 +98,20 @@ class CubeMapTexture: public AbstractTexture { */ explicit CubeMapTexture(): AbstractTexture(GL_TEXTURE_CUBE_MAP) {} + #ifndef MAGNUM_TARGET_GLES2 + /** @copydoc Texture::setBaseLevel() */ + CubeMapTexture& setBaseLevel(Int level) { + AbstractTexture::setBaseLevel(level); + return *this; + } + #endif + + /** @copydoc Texture::setMaxLevel() */ + CubeMapTexture& setMaxLevel(Int level) { + AbstractTexture::setMaxLevel(level); + return *this; + } + /** @copydoc Texture::setMinificationFilter() */ CubeMapTexture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); diff --git a/src/Magnum/CubeMapTextureArray.h b/src/Magnum/CubeMapTextureArray.h index 5ec43b656..a6c09f16a 100644 --- a/src/Magnum/CubeMapTextureArray.h +++ b/src/Magnum/CubeMapTextureArray.h @@ -89,6 +89,20 @@ class CubeMapTextureArray: public AbstractTexture { */ explicit CubeMapTextureArray(): AbstractTexture(GL_TEXTURE_CUBE_MAP_ARRAY) {} + #ifndef MAGNUM_TARGET_GLES2 + /** @copydoc Texture::setBaseLevel() */ + CubeMapTextureArray& setBaseLevel(Int level) { + AbstractTexture::setBaseLevel(level); + return *this; + } + #endif + + /** @copydoc Texture::setMaxLevel() */ + CubeMapTextureArray& setMaxLevel(Int level) { + AbstractTexture::setMaxLevel(level); + return *this; + } + /** @copydoc Texture::setMinificationFilter() */ CubeMapTextureArray& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); diff --git a/src/Magnum/Extensions.h b/src/Magnum/Extensions.h index 841d5710c..e2f07f16d 100644 --- a/src/Magnum/Extensions.h +++ b/src/Magnum/Extensions.h @@ -212,6 +212,9 @@ namespace GL { _extension(GL,APPLE,framebuffer_multisample, GLES200, GLES300) // #78 #endif _extension(GL,APPLE,texture_format_BGRA8888, GLES200, None) // #79 + #ifdef MAGNUM_TARGET_GLES2 + _extension(GL,APPLE,texture_max_level, GLES200, None) // #80 + #endif } namespace ARM { #ifdef MAGNUM_TARGET_GLES2 _extension(GL,ARM,rgba8, GLES200, GLES300) // #82 diff --git a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp index 94e187714..1d7e69a43 100644 --- a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp @@ -97,6 +97,8 @@ void CubeMapTextureArrayGLTest::sampling() { CubeMapTextureArray texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + .setBaseLevel(1) + .setMaxLevel(750) .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index a66ca896e..ede16a7f2 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -45,6 +45,9 @@ class CubeMapTextureGLTest: public AbstractOpenGLTester { void construct(); void sampling(); + #ifdef MAGNUM_TARGET_GLES2 + void samplingMaxLevel(); + #endif #ifndef MAGNUM_TARGET_GLES void samplingBorderInteger(); #endif @@ -71,6 +74,9 @@ CubeMapTextureGLTest::CubeMapTextureGLTest() { addTests({&CubeMapTextureGLTest::construct, &CubeMapTextureGLTest::sampling, + #ifdef MAGNUM_TARGET_GLES2 + &CubeMapTextureGLTest::samplingMaxLevel, + #endif #ifndef MAGNUM_TARGET_GLES &CubeMapTextureGLTest::samplingBorderInteger, #endif @@ -108,6 +114,10 @@ void CubeMapTextureGLTest::sampling() { CubeMapTexture texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + #ifndef MAGNUM_TARGET_GLES2 + .setBaseLevel(1) + .setMaxLevel(750) + #endif .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); @@ -115,6 +125,18 @@ void CubeMapTextureGLTest::sampling() { MAGNUM_VERIFY_NO_ERROR(); } +#ifdef MAGNUM_TARGET_GLES2 +void CubeMapTextureGLTest::samplingMaxLevel() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::APPLE::texture_max_level::string() + std::string(" is not supported.")); + + CubeMapTexture texture; + texture.setMaxLevel(750); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + #ifndef MAGNUM_TARGET_GLES void CubeMapTextureGLTest::samplingBorderInteger() { if(!Context::current()->isExtensionSupported()) diff --git a/src/Magnum/Test/TextureArrayGLTest.cpp b/src/Magnum/Test/TextureArrayGLTest.cpp index f0a81fbd3..2817bde22 100644 --- a/src/Magnum/Test/TextureArrayGLTest.cpp +++ b/src/Magnum/Test/TextureArrayGLTest.cpp @@ -50,6 +50,10 @@ class TextureArrayGLTest: public AbstractOpenGLTester { #endif void sampling2D(); + #ifdef MAGNUM_TARGET_GLES2 + void samplingMaxLevel2D(); + #endif + #ifndef MAGNUM_TARGET_GLES void samplingBorderInteger1D(); void samplingBorderInteger2D(); @@ -106,6 +110,10 @@ TextureArrayGLTest::TextureArrayGLTest() { #endif &TextureArrayGLTest::sampling2D, + #ifdef MAGNUM_TARGET_GLES2 + &TextureArrayGLTest::samplingMaxLevel2D, + #endif + #ifndef MAGNUM_TARGET_GLES &TextureArrayGLTest::samplingBorderInteger1D, &TextureArrayGLTest::samplingBorderInteger2D, @@ -189,6 +197,8 @@ void TextureArrayGLTest::sampling1D() { Texture1DArray texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + .setBaseLevel(1) + .setMaxLevel(750) .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); @@ -220,6 +230,10 @@ void TextureArrayGLTest::sampling2D() { Texture2DArray texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + #ifndef MAGNUM_TARGET_GLES2 + .setBaseLevel(1) + .setMaxLevel(750) + #endif #ifndef MAGNUM_TARGET_GLES .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) @@ -231,6 +245,18 @@ void TextureArrayGLTest::sampling2D() { MAGNUM_VERIFY_NO_ERROR(); } +#ifdef MAGNUM_TARGET_GLES2 +void TextureArrayGLTest::samplingMaxLevel2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::APPLE::texture_max_level::string() + std::string(" is not supported.")); + + Texture2DArray texture; + texture.setMaxLevel(750); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + #ifndef MAGNUM_TARGET_GLES void TextureArrayGLTest::samplingBorderInteger2D() { if(!Context::current()->isExtensionSupported()) diff --git a/src/Magnum/Test/TextureGLTest.cpp b/src/Magnum/Test/TextureGLTest.cpp index e208c4f8d..2f5a0f2ce 100644 --- a/src/Magnum/Test/TextureGLTest.cpp +++ b/src/Magnum/Test/TextureGLTest.cpp @@ -54,6 +54,11 @@ class TextureGLTest: public AbstractOpenGLTester { void sampling2D(); void sampling3D(); + #ifdef MAGNUM_TARGET_GLES2 + void samplingMaxLevel2D(); + void samplingMaxLevel3D(); + #endif + #ifndef MAGNUM_TARGET_GLES void samplingBorderInteger2D(); void samplingBorderInteger3D(); @@ -129,6 +134,11 @@ TextureGLTest::TextureGLTest() { &TextureGLTest::sampling2D, &TextureGLTest::sampling3D, + #ifdef MAGNUM_TARGET_GLES2 + &TextureGLTest::samplingMaxLevel2D, + &TextureGLTest::samplingMaxLevel3D, + #endif + #ifndef MAGNUM_TARGET_GLES &TextureGLTest::samplingBorderInteger2D, &TextureGLTest::samplingBorderInteger3D, @@ -234,6 +244,8 @@ void TextureGLTest::sampling1D() { Texture1D texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + .setBaseLevel(1) + .setMaxLevel(750) .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) .setMaxAnisotropy(Sampler::maxMaxAnisotropy()); @@ -246,6 +258,10 @@ void TextureGLTest::sampling2D() { Texture2D texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + #ifndef MAGNUM_TARGET_GLES2 + .setBaseLevel(1) + .setMaxLevel(750) + #endif #ifndef MAGNUM_TARGET_GLES .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) @@ -257,6 +273,18 @@ void TextureGLTest::sampling2D() { MAGNUM_VERIFY_NO_ERROR(); } +#ifdef MAGNUM_TARGET_GLES2 +void TextureGLTest::samplingMaxLevel2D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::APPLE::texture_max_level::string() + std::string(" is not supported.")); + + Texture2D texture; + texture.setMaxLevel(750); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + #ifndef MAGNUM_TARGET_GLES void TextureGLTest::samplingBorderInteger2D() { if(!Context::current()->isExtensionSupported()) @@ -293,6 +321,10 @@ void TextureGLTest::sampling3D() { Texture3D texture; texture.setMinificationFilter(Sampler::Filter::Linear, Sampler::Mipmap::Linear) .setMagnificationFilter(Sampler::Filter::Linear) + #ifndef MAGNUM_TARGET_GLES2 + .setBaseLevel(1) + .setMaxLevel(750) + #endif #ifndef MAGNUM_TARGET_GLES .setWrapping(Sampler::Wrapping::ClampToBorder) .setBorderColor(Color3(0.5f)) @@ -304,6 +336,20 @@ void TextureGLTest::sampling3D() { MAGNUM_VERIFY_NO_ERROR(); } +#ifdef MAGNUM_TARGET_GLES2 +void TextureGLTest::samplingMaxLevel3D() { + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::OES::texture_3D::string() + std::string(" is not supported.")); + if(!Context::current()->isExtensionSupported()) + CORRADE_SKIP(Extensions::GL::APPLE::texture_max_level::string() + std::string(" is not supported.")); + + Texture3D texture; + texture.setMaxLevel(750); + + MAGNUM_VERIFY_NO_ERROR(); +} +#endif + #ifndef MAGNUM_TARGET_GLES void TextureGLTest::samplingBorderInteger3D() { if(!Context::current()->isExtensionSupported()) diff --git a/src/Magnum/Texture.h b/src/Magnum/Texture.h index 0f1ecf236..2295f480e 100644 --- a/src/Magnum/Texture.h +++ b/src/Magnum/Texture.h @@ -77,10 +77,12 @@ texture.setMagnificationFilter(Sampler::Filter::Linear) .generateMipmap(); @endcode -@attention Note that default configuration (if @ref setMinificationFilter() is - not called with another value) is to use mipmaps, so be sure to either call - @ref setMinificationFilter(), explicitly specify all mip levels with - @ref setStorage() and @ref setImage() or call @ref generateMipmap(). +@attention Note that default configuration is to use mipmaps. Be sure to either + reduce mip level count using @ref setBaseLevel() and @ref setMaxLevel(), + explicitly allocate all mip levels using @ref setStorage(), call + @ref generateMipmap() after uploading the base level to generate the rest + of the mip chain or call @ref setMinificationFilter() with another value to + disable mipmapping. In shader, the texture is used via `sampler1D`/`sampler2D`/`sampler3D`, `sampler1DShadow`/`sampler2DShadow`/`sampler3DShadow`, @@ -184,6 +186,47 @@ template class Texture: public AbstractTexture { } #endif + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Set base mip level + * @return Reference to self (for method chaining) + * + * Taken into account when generating mipmap using @ref generateMipmap() + * and when considering texture completeness when using mipmap + * filtering. Initial value is `0`. + * @see @ref setMaxLevel(), @ref setMinificationFilter(), + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} + * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} + * with @def_gl{TEXTURE_BASE_LEVEL} + * @requires_gles30 Base level is always `0` in OpenGL ES 2.0. + */ + Texture& setBaseLevel(Int level) { + AbstractTexture::setBaseLevel(level); + return *this; + } + #endif + + /** + * @brief Set max mip level + * @return Reference to self (for method chaining) + * + * Taken into account when generating mipmap using @ref generateMipmap() + * and when considering texture completeness when using mipmap + * filtering. Initial value is `1000`, which is clamped to count of + * levels specified when using @ref setStorage(). + * @see @ref setBaseLevel(), @ref setMinificationFilter(), + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} + * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} + * with @def_gl{TEXTURE_MAX_LEVEL} + * @requires_gles30 %Extension @es_extension{APPLE,texture_max_level}, + * otherwise the max level is always set to largest possible value + * in OpenGL ES 2.0. + */ + Texture& setMaxLevel(Int level) { + AbstractTexture::setMaxLevel(level); + return *this; + } + /** * @brief Set minification filter * @param filter Filter @@ -197,9 +240,10 @@ template class Texture: public AbstractTexture { * available, the texture is bound to some texture unit before the * operation. Initial value is {@ref Sampler::Filter::Nearest, * @ref Sampler::Mipmap::Linear}. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} - * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} - * with @def_gl{TEXTURE_MIN_FILTER} + * @see @ref setBaseLevel(), @ref setMaxLevel(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_MIN_FILTER} */ Texture& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap); @@ -330,8 +374,8 @@ template class Texture: public AbstractTexture { * calls. * @todo allow the user to specify ColorType explicitly to avoid * issues in WebGL (see setSubImage()) - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and - * @fn_gl{TexStorage1D}/@fn_gl{TexStorage2D}/@fn_gl{TexStorage3D} + * @see @ref setMaxLevel(), @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}, diff --git a/src/Magnum/TextureArray.h b/src/Magnum/TextureArray.h index dcf983c14..064c08cf8 100644 --- a/src/Magnum/TextureArray.h +++ b/src/Magnum/TextureArray.h @@ -55,6 +55,8 @@ Template class for one- and two-dimensional texture arrays. See also @section Texture-usage Usage +See @ref Texture documentation for introduction. + Common usage is to fully configure all texture parameters and then set the data. Example configuration: @code @@ -77,11 +79,6 @@ for(std::size_t i = 0; i != 16; ++i) { } @endcode -@attention Note that default configuration (if @ref setMinificationFilter() is - not called with another value) is to use mipmaps, so be sure to either call - @ref setMinificationFilter(), explicitly specify all mip levels with - @ref setStorage() and @ref setImage() or call @ref generateMipmap(). - In shader, the texture is used via `sampler1DArray`/`sampler2DArray`, `sampler1DArrayShadow`/`sampler1DArrayShadow`, `isampler1DArray`/`isampler2DArray` or `usampler1DArray`/`usampler2DArray`. See @ref AbstractShaderProgram @@ -107,6 +104,20 @@ template class TextureArray: public AbstractTexture { */ explicit TextureArray(): AbstractTexture(Implementation::textureArrayTarget()) {} + #ifndef MAGNUM_TARGET_GLES2 + /** @copydoc Texture::setBaseLevel() */ + TextureArray& setBaseLevel(Int level) { + AbstractTexture::setBaseLevel(level); + return *this; + } + #endif + + /** @copydoc Texture::setMaxLevel() */ + TextureArray& setMaxLevel(Int level) { + AbstractTexture::setMaxLevel(level); + return *this; + } + /** @copydoc Texture::setMinificationFilter() */ TextureArray& setMinificationFilter(Sampler::Filter filter, Sampler::Mipmap mipmap = Sampler::Mipmap::Base) { AbstractTexture::setMinificationFilter(filter, mipmap);