diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index f4e31d568..419437537 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -151,42 +151,45 @@ void AbstractTexture::unbindImplementationDSA(const GLint textureUnit) { } #endif +void AbstractTexture::unbind(const Int firstTextureUnit, const std::size_t count) { + /* State tracker is updated in the implementations */ + Context::current()->state().texture->bindMultiImplementation(firstTextureUnit, {nullptr, count}); +} + +/** @todoc const std::initializer_list makes Doxygen grumpy */ void AbstractTexture::bind(const Int firstTextureUnit, std::initializer_list textures) { /* State tracker is updated in the implementations */ - Context::current()->state().texture->bindMultiImplementation(firstTextureUnit, textures); + Context::current()->state().texture->bindMultiImplementation(firstTextureUnit, {textures.begin(), textures.size()}); } -void AbstractTexture::bindImplementationFallback(const GLint firstTextureUnit, std::initializer_list textures) { - Int unit = firstTextureUnit; - for(AbstractTexture* const texture: textures) { - if(texture) texture->bind(unit); - else unbind(unit); - ++unit; - } +void AbstractTexture::bindImplementationFallback(const GLint firstTextureUnit, const Containers::ArrayReference textures) { + for(std::size_t i = 0; i != textures.size(); ++i) + textures && textures[i] ? textures[i]->bind(firstTextureUnit + i) : unbind(firstTextureUnit + i); } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::bindImplementationMulti(const GLint firstTextureUnit, std::initializer_list textures) { +void AbstractTexture::bindImplementationMulti(const GLint firstTextureUnit, const Containers::ArrayReference textures) { Implementation::TextureState* const textureState = Context::current()->state().texture; /* Create array of IDs and also update bindings in state tracker */ - Containers::Array ids{textures.size()}; - Int i{}; + Containers::Array ids{textures ? textures.size() : 0}; bool different = false; - for(AbstractTexture* const texture: textures) { - if(texture) texture->createIfNotAlready(); + for(std::size_t i = 0; i != textures.size(); ++i) { + const GLuint id = textures && textures[i] ? textures[i]->_id : 0; + + if(textures) { + if(textures[i]) textures[i]->createIfNotAlready(); + ids[i] = id; + } - const GLuint id = ids[i] = texture ? texture->_id : 0; if(textureState->bindings[firstTextureUnit + i].second != id) { different = true; textureState->bindings[firstTextureUnit + i].second = id; } - - ++i; } /* Avoid doing the binding if there is nothing different */ - if(different) glBindTextures(firstTextureUnit, ids.size(), ids); + if(different) glBindTextures(firstTextureUnit, textures.size(), ids); } #endif diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index fed9b90c5..4f2308490 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -203,6 +203,21 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { */ static void unbind(Int textureUnit); + /** + * @brief Unbind textures in given range of texture units + * + * Unbinds all texture in the range @f$ [ firstTextureUnit ; firstTextureUnit + count ) @f$. + * If @extension{ARB,multi_bind} (part of OpenGL 4.4) is not available, + * the feature is emulated with sequence of @ref unbind(Int) calls. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. + * @see @ref Shader::maxCombinedTextureImageUnits(), @fn_gl{BindTextures}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} or + * @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} + */ + static void unbind(Int firstTextureUnit, std::size_t count); + /** * @brief Bind textures to given range of texture units * @@ -210,12 +225,13 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { * `firstTextureUnit + 1` etc. If any texture is `nullptr`, given * texture unit is unbound. If @extension{ARB,multi_bind} (part of * OpenGL 4.4) is not available, the feature is emulated with sequence - * of @ref bind(Int) / @ref unbind() calls. + * of @ref bind(Int) / @ref unbind(Int) calls. * @note This function is meant to be used only internally from * @ref AbstractShaderProgram subclasses. See its documentation * for more information. - * @see @fn_gl{BindTextures}, eventually @fn_gl{ActiveTexture}, - * @fn_gl{BindTexture} or @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} + * @see @ref Shader::maxCombinedTextureImageUnits(), @fn_gl{BindTextures}, + * eventually @fn_gl{ActiveTexture}, @fn_gl{BindTexture} or + * @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} */ static void bind(Int firstTextureUnit, std::initializer_list textures); @@ -358,9 +374,9 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { static void MAGNUM_LOCAL unbindImplementationDSA(GLint textureUnit); #endif - static void MAGNUM_LOCAL bindImplementationFallback(GLint firstTextureUnit, std::initializer_list textures); + static void MAGNUM_LOCAL bindImplementationFallback(GLint firstTextureUnit, Containers::ArrayReference textures); #ifndef MAGNUM_TARGET_GLES - static void MAGNUM_LOCAL bindImplementationMulti(GLint firstTextureUnit, std::initializer_list textures); + static void MAGNUM_LOCAL bindImplementationMulti(GLint firstTextureUnit, Containers::ArrayReference textures); #endif void MAGNUM_LOCAL createIfNotAlready(); diff --git a/src/Magnum/Implementation/TextureState.h b/src/Magnum/Implementation/TextureState.h index b361d04fd..79650690a 100644 --- a/src/Magnum/Implementation/TextureState.h +++ b/src/Magnum/Implementation/TextureState.h @@ -40,7 +40,7 @@ struct TextureState { void reset(); void(*unbindImplementation)(GLint); - void(*bindMultiImplementation)(GLint, std::initializer_list); + void(*bindMultiImplementation)(GLint, Containers::ArrayReference); void(AbstractTexture::*bindImplementation)(GLint); void(AbstractTexture::*parameteriImplementation)(GLenum, GLint); void(AbstractTexture::*parameterfImplementation)(GLenum, GLfloat); diff --git a/src/Magnum/Test/BufferTextureGLTest.cpp b/src/Magnum/Test/BufferTextureGLTest.cpp index 710c6b5a3..4c74c33fb 100644 --- a/src/Magnum/Test/BufferTextureGLTest.cpp +++ b/src/Magnum/Test/BufferTextureGLTest.cpp @@ -78,6 +78,10 @@ void BufferTextureGLTest::bind() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } void BufferTextureGLTest::setBuffer() { diff --git a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp index 908ae7cc9..6ec415ff8 100644 --- a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp @@ -114,6 +114,10 @@ void CubeMapTextureArrayGLTest::bind() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } void CubeMapTextureArrayGLTest::sampling() { diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index d93507960..e71d10b2c 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -139,6 +139,10 @@ void CubeMapTextureGLTest::bind() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } void CubeMapTextureGLTest::sampling() { diff --git a/src/Magnum/Test/MultisampleTextureGLTest.cpp b/src/Magnum/Test/MultisampleTextureGLTest.cpp index 0ccde3e5e..c90cc8de3 100644 --- a/src/Magnum/Test/MultisampleTextureGLTest.cpp +++ b/src/Magnum/Test/MultisampleTextureGLTest.cpp @@ -146,6 +146,10 @@ void MultisampleTextureGLTest::bind2D() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } #ifndef MAGNUM_TARGET_GLES @@ -165,6 +169,10 @@ void MultisampleTextureGLTest::bind2DArray() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } #endif diff --git a/src/Magnum/Test/RectangleTextureGLTest.cpp b/src/Magnum/Test/RectangleTextureGLTest.cpp index 0bc52e25a..1af159aea 100644 --- a/src/Magnum/Test/RectangleTextureGLTest.cpp +++ b/src/Magnum/Test/RectangleTextureGLTest.cpp @@ -112,6 +112,10 @@ void RectangleTextureGLTest::bind() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } void RectangleTextureGLTest::sampling() { diff --git a/src/Magnum/Test/TextureArrayGLTest.cpp b/src/Magnum/Test/TextureArrayGLTest.cpp index 775bfcc91..af82f9db3 100644 --- a/src/Magnum/Test/TextureArrayGLTest.cpp +++ b/src/Magnum/Test/TextureArrayGLTest.cpp @@ -244,6 +244,10 @@ void TextureArrayGLTest::bind1D() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } #endif @@ -265,6 +269,10 @@ void TextureArrayGLTest::bind2D() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Test/TextureGLTest.cpp b/src/Magnum/Test/TextureGLTest.cpp index 7fe72cfb5..7a422e78e 100644 --- a/src/Magnum/Test/TextureGLTest.cpp +++ b/src/Magnum/Test/TextureGLTest.cpp @@ -303,6 +303,10 @@ void TextureGLTest::bind1D() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } #endif @@ -319,6 +323,10 @@ void TextureGLTest::bind2D() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } void TextureGLTest::bind3D() { @@ -339,6 +347,10 @@ void TextureGLTest::bind3D() { AbstractTexture::bind(7, {&texture, nullptr, &texture}); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(7, 3); + + MAGNUM_VERIFY_NO_ERROR(); } #ifndef MAGNUM_TARGET_GLES