diff --git a/doc/opengl-support.dox b/doc/opengl-support.dox index 96444d692..6ec01fbe5 100644 --- a/doc/opengl-support.dox +++ b/doc/opengl-support.dox @@ -201,7 +201,7 @@ following: @extension{ARB,buffer_storage} | | @extension{ARB,clear_texture} | | @extension{ARB,enhanced_layouts} | done (shading language only) -@extension{ARB,multi_bind} | only single texture binding +@extension{ARB,multi_bind} | only texture binding @extension{ARB,query_buffer_object} | | @extension{ARB,texture_mirror_clamp_to_edge} | done @extension{ARB,texture_stencil8} | done diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index 93d74dacc..c940f0580 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -127,6 +127,36 @@ void AbstractTexture::unbindImplementationDSA(const GLint textureUnit) { } #endif +void AbstractTexture::bind(const Int firstTextureUnit, std::initializer_list textures) { + /* State tracker is updated in the implementations */ + Context::current()->state().texture->bindMultiImplementation(firstTextureUnit, textures); +} + +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; + } +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::bindImplementationMulti(const GLint firstTextureUnit, std::initializer_list 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{}; + for(const AbstractTexture* const texture: textures) { + textureState->bindings[firstTextureUnit + i].second = ids[i] = texture ? texture->id() : 0; + ++i; + } + + glBindTextures(firstTextureUnit, ids.size(), ids); +} +#endif + AbstractTexture::AbstractTexture(GLenum target): _target(target) { glGenTextures(1, &_id); } diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index 099a74d35..b708473be 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -172,6 +172,19 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { */ static void unbind(Int textureUnit); + /** + * @brief Bind textures to given range of texture units + * + * Binds first texture in the list to @p firstTextureUnit, second to + * `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. + * @see @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); + /** @brief Copying is not allowed */ AbstractTexture(const AbstractTexture&) = delete; @@ -230,7 +243,8 @@ 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 unbind(), @ref Shader::maxCombinedTextureImageUnits(), + * @see @ref bind(Int, std::initializer_list), + * @ref unbind(), @ref Shader::maxCombinedTextureImageUnits(), * @fn_gl{ActiveTexture}, @fn_gl{BindTexture}, @fn_gl{BindTextures} * or @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} */ @@ -275,6 +289,11 @@ 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); + #ifndef MAGNUM_TARGET_GLES + static void MAGNUM_LOCAL bindImplementationMulti(GLint firstTextureUnit, std::initializer_list textures); + #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 23aafcfe1..e83e195e5 100644 --- a/src/Magnum/Implementation/TextureState.cpp +++ b/src/Magnum/Implementation/TextureState.cpp @@ -47,18 +47,21 @@ TextureState::TextureState(Context& context, std::vector& extension extensions.push_back(Extensions::GL::ARB::multi_bind::string()); unbindImplementation = &AbstractTexture::unbindImplementationMulti; + bindMultiImplementation = &AbstractTexture::bindImplementationMulti; bindImplementation = &AbstractTexture::bindImplementationMulti; } else if(context.isExtensionSupported()) { /* Extension name added below */ unbindImplementation = &AbstractTexture::unbindImplementationDSA; + bindMultiImplementation = &AbstractTexture::bindImplementationFallback; bindImplementation = &AbstractTexture::bindImplementationDSA; } else #endif { unbindImplementation = &AbstractTexture::unbindImplementationDefault; + bindMultiImplementation = &AbstractTexture::bindImplementationFallback; bindImplementation = &AbstractTexture::bindImplementationDefault; } diff --git a/src/Magnum/Implementation/TextureState.h b/src/Magnum/Implementation/TextureState.h index 3fb4af551..098080fb0 100644 --- a/src/Magnum/Implementation/TextureState.h +++ b/src/Magnum/Implementation/TextureState.h @@ -38,6 +38,7 @@ struct TextureState { ~TextureState(); void(*unbindImplementation)(GLint); + void(*bindMultiImplementation)(GLint, std::initializer_list); 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 1eb02c535..b67180ea9 100644 --- a/src/Magnum/Test/BufferTextureGLTest.cpp +++ b/src/Magnum/Test/BufferTextureGLTest.cpp @@ -74,6 +74,10 @@ void BufferTextureGLTest::bind() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } void BufferTextureGLTest::setBuffer() { diff --git a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp index 5ee8b18d2..fbe7e7f5c 100644 --- a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp @@ -101,6 +101,10 @@ void CubeMapTextureArrayGLTest::bind() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } void CubeMapTextureArrayGLTest::sampling() { diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index a8631da68..092d6b5e4 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -121,6 +121,10 @@ void CubeMapTextureGLTest::bind() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } void CubeMapTextureGLTest::sampling() { diff --git a/src/Magnum/Test/MultisampleTextureGLTest.cpp b/src/Magnum/Test/MultisampleTextureGLTest.cpp index e2df0e503..0de1a3d44 100644 --- a/src/Magnum/Test/MultisampleTextureGLTest.cpp +++ b/src/Magnum/Test/MultisampleTextureGLTest.cpp @@ -127,6 +127,10 @@ void MultisampleTextureGLTest::bind2D() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::bind2DArray() { @@ -141,6 +145,10 @@ void MultisampleTextureGLTest::bind2DArray() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } void MultisampleTextureGLTest::storage2D() { diff --git a/src/Magnum/Test/RectangleTextureGLTest.cpp b/src/Magnum/Test/RectangleTextureGLTest.cpp index b7a54c2e3..a0a9827c3 100644 --- a/src/Magnum/Test/RectangleTextureGLTest.cpp +++ b/src/Magnum/Test/RectangleTextureGLTest.cpp @@ -102,6 +102,10 @@ void RectangleTextureGLTest::bind() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } void RectangleTextureGLTest::sampling() { diff --git a/src/Magnum/Test/TextureArrayGLTest.cpp b/src/Magnum/Test/TextureArrayGLTest.cpp index 38e286dba..0a7f7676b 100644 --- a/src/Magnum/Test/TextureArrayGLTest.cpp +++ b/src/Magnum/Test/TextureArrayGLTest.cpp @@ -212,6 +212,10 @@ void TextureArrayGLTest::bind1D() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } #endif @@ -229,6 +233,10 @@ void TextureArrayGLTest::bind2D() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } #ifndef MAGNUM_TARGET_GLES diff --git a/src/Magnum/Test/TextureGLTest.cpp b/src/Magnum/Test/TextureGLTest.cpp index cabcf2de4..fb5a90b5b 100644 --- a/src/Magnum/Test/TextureGLTest.cpp +++ b/src/Magnum/Test/TextureGLTest.cpp @@ -261,6 +261,10 @@ void TextureGLTest::bind1D() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } #endif @@ -273,6 +277,10 @@ void TextureGLTest::bind2D() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } void TextureGLTest::bind3D() { @@ -289,6 +297,10 @@ void TextureGLTest::bind3D() { AbstractTexture::unbind(15); MAGNUM_VERIFY_NO_ERROR(); + + AbstractTexture::bind(7, {&texture, nullptr, &texture}); + + MAGNUM_VERIFY_NO_ERROR(); } #ifndef MAGNUM_TARGET_GLES