diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index 7ce9d4e98..93d74dacc 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -91,6 +91,42 @@ Int AbstractTexture::maxIntegerSamples() { } #endif +void AbstractTexture::unbind(const Int textureUnit) { + Implementation::TextureState* const textureState = Context::current()->state().texture; + + /* If given texture unit is already unbound, nothing to do */ + if(textureState->bindings[textureUnit].second == 0) return; + + /* Unbind the texture, reset state tracker */ + Context::current()->state().texture->unbindImplementation(textureUnit); + textureState->bindings[textureUnit] = {}; +} + +void AbstractTexture::unbindImplementationDefault(const GLint textureUnit) { + Implementation::TextureState* const textureState = Context::current()->state().texture; + + /* Activate given texture unit if not already active, update state tracker */ + if(textureState->currentTextureUnit != textureUnit) + glActiveTexture(GL_TEXTURE0 + (textureState->currentTextureUnit = textureUnit)); + + CORRADE_INTERNAL_ASSERT(textureState->bindings[textureUnit].first != 0); + glBindTexture(textureState->bindings[textureUnit].first, 0); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::unbindImplementationMulti(const GLint textureUnit) { + constexpr static const GLuint zero = 0; + glBindTextures(textureUnit, 1, &zero); +} + +void AbstractTexture::unbindImplementationDSA(const GLint textureUnit) { + Implementation::TextureState* const textureState = Context::current()->state().texture; + + CORRADE_INTERNAL_ASSERT(textureState->bindings[textureUnit].first != 0); + glBindMultiTextureEXT(GL_TEXTURE0 + textureUnit, textureState->bindings[textureUnit].first, 0); +} +#endif + AbstractTexture::AbstractTexture(GLenum target): _target(target) { glGenTextures(1, &_id); } diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index ea95a9706..099a74d35 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -157,6 +157,21 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { static Int maxIntegerSamples(); #endif + /** + * @brief Unbind any texture from given texture unit + * + * If @extension{ARB,multi_bind} (part of OpenGL 4.4) or + * @extension{EXT,direct_state_access} is not available, the texture + * unit is made active before binding the texture. + * @note This function is meant to be used only internally from + * @ref AbstractShaderProgram subclasses. See its documentation + * for more information. + * @see @ref bind(), @ref Shader::maxCombinedTextureImageUnits(), + * @fn_gl{ActiveTexture}, @fn_gl{BindTexture}, @fn_gl{BindTextures} + * or @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} + */ + static void unbind(Int textureUnit); + /** @brief Copying is not allowed */ AbstractTexture(const AbstractTexture&) = delete; @@ -215,7 +230,7 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { * @note This function is meant to be used only internally from * @ref AbstractShaderProgram subclasses. See its documentation * for more information. - * @see @ref Shader::maxCombinedTextureImageUnits(), + * @see @ref unbind(), @ref Shader::maxCombinedTextureImageUnits(), * @fn_gl{ActiveTexture}, @fn_gl{BindTexture}, @fn_gl{BindTextures} * or @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} */ @@ -254,6 +269,12 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { GLenum _target; private: + static void MAGNUM_LOCAL unbindImplementationDefault(GLint textureUnit); + #ifndef MAGNUM_TARGET_GLES + static void MAGNUM_LOCAL unbindImplementationMulti(GLint textureUnit); + static void MAGNUM_LOCAL unbindImplementationDSA(GLint textureUnit); + #endif + void MAGNUM_LOCAL bindImplementationDefault(GLint textureUnit); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL bindImplementationMulti(GLint textureUnit); diff --git a/src/Magnum/Implementation/TextureState.cpp b/src/Magnum/Implementation/TextureState.cpp index beae61381..23aafcfe1 100644 --- a/src/Magnum/Implementation/TextureState.cpp +++ b/src/Magnum/Implementation/TextureState.cpp @@ -45,13 +45,20 @@ TextureState::TextureState(Context& context, std::vector& extension #ifndef MAGNUM_TARGET_GLES if(context.isExtensionSupported()) { extensions.push_back(Extensions::GL::ARB::multi_bind::string()); + + unbindImplementation = &AbstractTexture::unbindImplementationMulti; bindImplementation = &AbstractTexture::bindImplementationMulti; + } else if(context.isExtensionSupported()) { /* Extension name added below */ + + unbindImplementation = &AbstractTexture::unbindImplementationDSA; bindImplementation = &AbstractTexture::bindImplementationDSA; + } else #endif { + unbindImplementation = &AbstractTexture::unbindImplementationDefault; bindImplementation = &AbstractTexture::bindImplementationDefault; } diff --git a/src/Magnum/Implementation/TextureState.h b/src/Magnum/Implementation/TextureState.h index 9cb56fa46..3fb4af551 100644 --- a/src/Magnum/Implementation/TextureState.h +++ b/src/Magnum/Implementation/TextureState.h @@ -37,6 +37,7 @@ struct TextureState { explicit TextureState(Context& context, std::vector& extensions); ~TextureState(); + void(*unbindImplementation)(GLint); 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 e61f38e62..1eb02c535 100644 --- a/src/Magnum/Test/BufferTextureGLTest.cpp +++ b/src/Magnum/Test/BufferTextureGLTest.cpp @@ -70,6 +70,10 @@ void BufferTextureGLTest::bind() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } void BufferTextureGLTest::setBuffer() { diff --git a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp index 9e353ca7d..5ee8b18d2 100644 --- a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp @@ -97,6 +97,10 @@ void CubeMapTextureArrayGLTest::bind() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } void CubeMapTextureArrayGLTest::sampling() { diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index ac99f0cee..a8631da68 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -117,6 +117,10 @@ void CubeMapTextureGLTest::bind() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } void CubeMapTextureGLTest::sampling() { diff --git a/src/Magnum/Test/MultisampleTextureGLTest.cpp b/src/Magnum/Test/MultisampleTextureGLTest.cpp index fbfd5d759..e2df0e503 100644 --- a/src/Magnum/Test/MultisampleTextureGLTest.cpp +++ b/src/Magnum/Test/MultisampleTextureGLTest.cpp @@ -123,6 +123,10 @@ void MultisampleTextureGLTest::bind2D() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::bind2DArray() { @@ -133,6 +137,10 @@ void MultisampleTextureGLTest::bind2DArray() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::storage2D() { diff --git a/src/Magnum/Test/RectangleTextureGLTest.cpp b/src/Magnum/Test/RectangleTextureGLTest.cpp index 7068671c5..b7a54c2e3 100644 --- a/src/Magnum/Test/RectangleTextureGLTest.cpp +++ b/src/Magnum/Test/RectangleTextureGLTest.cpp @@ -98,6 +98,10 @@ void RectangleTextureGLTest::bind() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } void RectangleTextureGLTest::sampling() { diff --git a/src/Magnum/Test/TextureArrayGLTest.cpp b/src/Magnum/Test/TextureArrayGLTest.cpp index 33ff280db..38e286dba 100644 --- a/src/Magnum/Test/TextureArrayGLTest.cpp +++ b/src/Magnum/Test/TextureArrayGLTest.cpp @@ -208,6 +208,10 @@ void TextureArrayGLTest::bind1D() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } #endif @@ -221,6 +225,10 @@ void TextureArrayGLTest::bind2D() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Test/TextureGLTest.cpp b/src/Magnum/Test/TextureGLTest.cpp index 2cfa992a3..cabcf2de4 100644 --- a/src/Magnum/Test/TextureGLTest.cpp +++ b/src/Magnum/Test/TextureGLTest.cpp @@ -257,6 +257,10 @@ void TextureGLTest::bind1D() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } #endif @@ -265,6 +269,10 @@ void TextureGLTest::bind2D() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } void TextureGLTest::bind3D() { @@ -277,6 +285,10 @@ void TextureGLTest::bind3D() { texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::unbind(15); + + MAGNUM_VERIFY_NO_ERROR(); } #ifndef MAGNUM_TARGET_GLES