diff --git a/src/AbstractTexture.cpp b/src/AbstractTexture.cpp index 0822455e0..6cb0ca856 100644 --- a/src/AbstractTexture.cpp +++ b/src/AbstractTexture.cpp @@ -16,11 +16,35 @@ #include "AbstractTexture.h" #include "Context.h" +#include "Extensions.h" #include "Implementation/State.h" #include "Implementation/TextureState.h" namespace Magnum { +AbstractTexture::BindImplementation AbstractTexture::bindImplementation = + &AbstractTexture::bindImplementationDefault; +AbstractTexture::ParameteriImplementation AbstractTexture::parameteriImplementation = + &AbstractTexture::parameterImplementationDefault; +AbstractTexture::ParameterfImplementation AbstractTexture::parameterfImplementation = + &AbstractTexture::parameterImplementationDefault; +AbstractTexture::ParameterfvImplementation AbstractTexture::parameterfvImplementation = + &AbstractTexture::parameterImplementationDefault; +AbstractTexture::MipmapImplementation AbstractTexture::mipmapImplementation = + &AbstractTexture::mipmapImplementationDefault; +AbstractTexture::Image1DImplementation AbstractTexture::image1DImplementation = + &AbstractTexture::imageImplementationDefault; +AbstractTexture::Image2DImplementation AbstractTexture::image2DImplementation = + &AbstractTexture::imageImplementationDefault; +AbstractTexture::Image3DImplementation AbstractTexture::image3DImplementation = + &AbstractTexture::imageImplementationDefault; +AbstractTexture::SubImage1DImplementation AbstractTexture::subImage1DImplementation = + &AbstractTexture::subImageImplementationDefault; +AbstractTexture::SubImage2DImplementation AbstractTexture::subImage2DImplementation = + &AbstractTexture::subImageImplementationDefault; +AbstractTexture::SubImage3DImplementation AbstractTexture::subImage3DImplementation = + &AbstractTexture::subImageImplementationDefault; + #ifndef DOXYGEN_GENERATING_OUTPUT /* Check correctness of binary OR in setMinificationFilter(). If nobody fucks @@ -68,6 +92,12 @@ void AbstractTexture::bind(GLint layer) { /* If already bound in given layer, nothing to do */ if(textureState->bindings[layer] == _id) return; + (this->*bindImplementation)(layer); +} + +void AbstractTexture::bindImplementationDefault(GLint layer) { + Implementation::TextureState* const textureState = Context::current()->state()->texture; + /* Change to given layer, if not already there */ if(textureState->currentLayer != layer) glActiveTexture(GL_TEXTURE0 + (textureState->currentLayer = layer)); @@ -76,13 +106,16 @@ void AbstractTexture::bind(GLint layer) { glBindTexture(_target, (textureState->bindings[layer] = _id)); } +void AbstractTexture::bindImplementationDSA(GLint layer) { + glBindMultiTextureEXT(GL_TEXTURE0 + layer, _target, (Context::current()->state()->texture->bindings[layer] = _id)); +} + AbstractTexture* AbstractTexture::setMinificationFilter(Filter filter, Mipmap mipmap) { #ifndef MAGNUM_TARGET_GLES CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE || mipmap == Mipmap::BaseLevel, "AbstractTexture: rectangle textures cannot have mipmaps", this); #endif - bindInternal(); - glTexParameteri(_target, GL_TEXTURE_MIN_FILTER, + (this->*parameteriImplementation)(GL_TEXTURE_MIN_FILTER, static_cast(filter)|static_cast(mipmap)); return this; } @@ -92,9 +125,17 @@ AbstractTexture* AbstractTexture::generateMipmap() { CORRADE_ASSERT(_target != GL_TEXTURE_RECTANGLE, "AbstractTexture: rectangle textures cannot have mipmaps", this); #endif + (this->*mipmapImplementation)(); + return this; +} + +void AbstractTexture::mipmapImplementationDefault() { bindInternal(); glGenerateMipmap(_target); - return this; +} + +void AbstractTexture::mipmapImplementationDSA() { + glGenerateTextureMipmapEXT(_id, _target); } #ifndef DOXYGEN_GENERATING_OUTPUT @@ -123,6 +164,103 @@ void AbstractTexture::initializeContextBasedFunctionality(Context* context) { /* Get the value and resize bindings array */ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &value); textureState->bindings.resize(value); + + if(context->isExtensionSupported()) { + Debug() << "AbstractTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + bindImplementation = &AbstractTexture::bindImplementationDSA; + parameteriImplementation = &AbstractTexture::parameterImplementationDSA; + parameterfImplementation = &AbstractTexture::parameterImplementationDSA; + parameterfvImplementation = &AbstractTexture::parameterImplementationDSA; + mipmapImplementation = &AbstractTexture::mipmapImplementationDSA; + image1DImplementation = &AbstractTexture::imageImplementationDSA; + image2DImplementation = &AbstractTexture::imageImplementationDSA; + image3DImplementation = &AbstractTexture::imageImplementationDSA; + subImage1DImplementation = &AbstractTexture::subImageImplementationDSA; + subImage2DImplementation = &AbstractTexture::subImageImplementationDSA; + subImage3DImplementation = &AbstractTexture::subImageImplementationDSA; + } +} + +void AbstractTexture::parameterImplementationDefault(GLenum parameter, GLint value) { + bindInternal(); + glTexParameteri(_target, parameter, value); +} + +void AbstractTexture::parameterImplementationDSA(GLenum parameter, GLint value) { + glTextureParameteriEXT(_id, _target, parameter, value); +} + +void AbstractTexture::parameterImplementationDefault(GLenum parameter, GLfloat value) { + bindInternal(); + glTexParameterf(_target, parameter, value); +} + +void AbstractTexture::parameterImplementationDSA(GLenum parameter, GLfloat value) { + glTextureParameterfEXT(_id, _target, parameter, value); +} + +void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLfloat* values) { + bindInternal(); + glTexParameterfv(_target, parameter, values); +} + +void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLfloat* values) { + glTextureParameterfvEXT(_id, _target, parameter, values); +} + +void AbstractTexture::imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + bindInternal(); + glTexImage1D(target, mipLevel, internalFormat, size[0], 0, static_cast(components), static_cast(type), data); +} + +void AbstractTexture::imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + glTextureImage1DEXT(_id, target, mipLevel, internalFormat, size[0], 0, static_cast(components), static_cast(type), data); +} + +void AbstractTexture::imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + bindInternal(); + glTexImage2D(target, mipLevel, internalFormat, size.x(), size.y(), 0, static_cast(components), static_cast(type), data); +} + +void AbstractTexture::imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + glTextureImage2DEXT(_id, target, mipLevel, internalFormat, size.x(), size.y(), 0, static_cast(components), static_cast(type), data); +} + +void AbstractTexture::imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + bindInternal(); + glTexImage3D(target, mipLevel, internalFormat, size.x(), size.y(), size.z(), 0, static_cast(components), static_cast(type), data); +} + +void AbstractTexture::imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + glTextureImage3DEXT(_id, target, mipLevel, internalFormat, size.x(), size.y(), size.z(), 0, static_cast(components), static_cast(type), data); +} + +void AbstractTexture::subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + bindInternal(); + glTexSubImage1D(target, mipLevel, offset[0], size[0], static_cast(components), static_cast(type), data); +} + +void AbstractTexture::subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + glTextureSubImage1DEXT(_id, target, mipLevel, offset[0], size[0], static_cast(components), static_cast(type), data); +} + +void AbstractTexture::subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + bindInternal(); + glTexSubImage2D(target, mipLevel, offset.x(), offset.y(), size.x(), size.y(), static_cast(components), static_cast(type), data); +} + +void AbstractTexture::subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + glTextureSubImage2DEXT(_id, target, mipLevel, offset.x(), offset.y(), size.x(), size.y(), static_cast(components), static_cast(type), data); +} + +void AbstractTexture::subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector3& offset, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + bindInternal(); + glTexSubImage3D(target, mipLevel, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast(components), static_cast(type), data); +} + +void AbstractTexture::subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector3& offset, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data) { + glTextureSubImage3DEXT(_id, target, mipLevel, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), static_cast(components), static_cast(type), data); } AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components components, AbstractTexture::ComponentType type) { @@ -189,22 +327,20 @@ AbstractTexture::InternalFormat::InternalFormat(AbstractTexture::Components comp } #ifndef DOXYGEN_GENERATING_OUTPUT -void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Math::Vector<2, Wrapping>& wrapping) { +void AbstractTexture::DataHelper<2>::setWrapping(AbstractTexture* texture, const Math::Vector2& wrapping) { #ifndef MAGNUM_TARGET_GLES CORRADE_ASSERT(texture->_target != GL_TEXTURE_RECTANGLE || ((wrapping[0] == Wrapping::ClampToEdge || wrapping[0] == Wrapping::ClampToBorder) && (wrapping[0] == Wrapping::ClampToEdge || wrapping[1] == Wrapping::ClampToEdge)), "AbstractTexture: rectangle texture wrapping must either clamp to border or to edge", ); #endif - texture->bindInternal(); - glTexParameteri(texture->_target, GL_TEXTURE_WRAP_S, static_cast(wrapping[0])); - glTexParameteri(texture->_target, GL_TEXTURE_WRAP_T, static_cast(wrapping[1])); + (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast(wrapping.x())); + (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, static_cast(wrapping.y())); } -void AbstractTexture::DataHelper<3>::setWrapping(AbstractTexture* texture, const Math::Vector<3, Wrapping>& wrapping) { - texture->bindInternal(); - glTexParameteri(texture->_target, GL_TEXTURE_WRAP_S, static_cast(wrapping[0])); - glTexParameteri(texture->_target, GL_TEXTURE_WRAP_T, static_cast(wrapping[1])); +void AbstractTexture::DataHelper<3>::setWrapping(AbstractTexture* texture, const Math::Vector3& wrapping) { + (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast(wrapping.x())); + (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_T, static_cast(wrapping.y())); #ifndef MAGNUM_TARGET_GLES - glTexParameteri(texture->_target, GL_TEXTURE_WRAP_R, static_cast(wrapping[2])); + (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_R, static_cast(wrapping.z())); #endif } #endif diff --git a/src/AbstractTexture.h b/src/AbstractTexture.h index a0ad2e615..c9e4b16ec 100644 --- a/src/AbstractTexture.h +++ b/src/AbstractTexture.h @@ -23,6 +23,7 @@ #include "Magnum.h" #include "Color.h" +#include "AbstractImage.h" namespace Magnum { @@ -52,6 +53,12 @@ affect active bindings in user layers. %Texture limits (such as maxSupportedLayerCount()) are cached, so repeated queries don't result in 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. + 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. @@ -592,8 +599,11 @@ class MAGNUM_EXPORT AbstractTexture { * * Sets current texture as active in given layer. The layer must be * between 0 and maxSupportedLayerCount(). Note that only one texture - * can be bound to given layer. - * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} + * can be bound to given layer. If @extension{EXT,direct_state_access} + * is not available, the layer is made active before binding the + * texture. + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} or + * @fn_gl_extension{BindMultiTexture,EXT,direct_state_access} */ void bind(GLint layer); @@ -606,12 +616,15 @@ class MAGNUM_EXPORT AbstractTexture { * @return Pointer to self (for method chaining) * * Sets filter used when the object pixel size is smaller than the - * texture size. + * texture size. If @extension{EXT,direct_state_access} is not + * available, the texture is bound to some layer before the operation. * @attention For rectangle textures only some modes are supported, - * see @ref AbstractTexture::Filter "Filter" and - * @ref AbstractTexture::Mipmap "Mipmap" documentation for more - * information. - * @see bind(), @fn_gl{TexParameter} with @def_gl{TEXTURE_MIN_FILTER} + * see @ref AbstractTexture::Filter "Filter" and + * @ref AbstractTexture::Mipmap "Mipmap" documentation for more + * information. + * @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} */ AbstractTexture* setMinificationFilter(Filter filter, Mipmap mipmap = Mipmap::BaseLevel); @@ -621,12 +634,14 @@ class MAGNUM_EXPORT AbstractTexture { * @return Pointer to self (for method chaining) * * Sets filter used when the object pixel size is larger than largest - * texture size. - * @see bind(), @fn_gl{TexParameter} with @def_gl{TEXTURE_MAG_FILTER} + * texture size. 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{TexParameter} + * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} + * with @def_gl{TEXTURE_MAG_FILTER} */ inline AbstractTexture* setMagnificationFilter(Filter filter) { - bindInternal(); - glTexParameteri(_target, GL_TEXTURE_MAG_FILTER, static_cast(filter)); + (this->*parameteriImplementation)(GL_TEXTURE_MAG_FILTER, static_cast(filter)); return this; } @@ -636,13 +651,15 @@ class MAGNUM_EXPORT AbstractTexture { * @return Pointer to self (for method chaining) * * Border color when @ref AbstractTexture::Wrapping "wrapping" is set - * to `ClampToBorder`. - * @see bind(), @fn_gl{TexParameter} with @def_gl{TEXTURE_BORDER_COLOR} + * to `ClampToBorder`. 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{TexParameter} + * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} + * with @def_gl{TEXTURE_BORDER_COLOR} * @requires_gl */ inline AbstractTexture* setBorderColor(const Color4& color) { - bindInternal(); - glTexParameterfv(_target, GL_TEXTURE_BORDER_COLOR, color.data()); + (this->*parameterfvImplementation)(GL_TEXTURE_BORDER_COLOR, color.data()); return this; } @@ -650,15 +667,19 @@ class MAGNUM_EXPORT AbstractTexture { * @brief Set max anisotropy * @return Pointer to self (for method chaining) * - * Default value is `1.0`, which means no anisotropy. Set to value - * greater than `1.0` for anisotropic filtering. - * @see maxSupportedAnisotropy(), bind(), @fn_gl{TexParameter} with @def_gl{TEXTURE_MAX_ANISOTROPY_EXT} + * Default value is `1.0f`, which means no anisotropy. Set to value + * greater than `1.0f` for anisotropic filtering. If + * @extension{EXT,direct_state_access} is not available, the texture + * is bound to some layer before the operation. + * @see maxSupportedAnisotropy(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{TexParameter} or + * @fn_gl_extension{TextureParameter,EXT,direct_state_access} with + * @def_gl{TEXTURE_MAX_ANISOTROPY_EXT} * @requires_gl * @requires_extension @extension{EXT,texture_filter_anisotropic} */ inline AbstractTexture* setMaxAnisotropy(GLfloat anisotropy) { - bindInternal(); - glTexParameterf(_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); + (this->*parameterfImplementation)(GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); return this; } #endif @@ -667,8 +688,12 @@ class MAGNUM_EXPORT AbstractTexture { * @brief Generate mipmap * @return Pointer to self (for method chaining) * - * Can not be used for rectangle textures. - * @see setMinificationFilter(), @fn_gl{GenerateMipmap} + * Can not be used for rectangle textures. If + * @extension{EXT,direct_state_access} is not available, the texture + * is bound to some layer before the operation. + * @see setMinificationFilter(), @fn_gl{ActiveTexture}, + * @fn_gl{BindTexture} and @fn_gl{GenerateMipmap} or + * @fn_gl_extension{GenerateTextureMipmap,EXT,direct_state_access} * @requires_gl30 Extension @extension{EXT,framebuffer_object} */ AbstractTexture* generateMipmap(); @@ -678,7 +703,7 @@ class MAGNUM_EXPORT AbstractTexture { template struct DataHelper {}; /* Unlike bind() this also sets the binding layer as active */ - void bindInternal(); + void MAGNUM_LOCAL bindInternal(); const GLenum _target; #endif @@ -686,6 +711,61 @@ class MAGNUM_EXPORT AbstractTexture { private: static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + typedef void(AbstractTexture::*BindImplementation)(GLint); + void MAGNUM_LOCAL bindImplementationDefault(GLint layer); + void MAGNUM_LOCAL bindImplementationDSA(GLint layer); + static MAGNUM_LOCAL BindImplementation bindImplementation; + + typedef void(AbstractTexture::*ParameteriImplementation)(GLenum, GLint); + void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLint value); + void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLint value); + static ParameteriImplementation parameteriImplementation; + + typedef void(AbstractTexture::*ParameterfImplementation)(GLenum, GLfloat); + void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, GLfloat value); + void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, GLfloat value); + static ParameterfImplementation parameterfImplementation; + + typedef void(AbstractTexture::*ParameterfvImplementation)(GLenum, const GLfloat*); + void MAGNUM_LOCAL parameterImplementationDefault(GLenum parameter, const GLfloat* values); + void MAGNUM_LOCAL parameterImplementationDSA(GLenum parameter, const GLfloat* values); + static ParameterfvImplementation parameterfvImplementation; + + typedef void(AbstractTexture::*MipmapImplementation)(); + void MAGNUM_LOCAL mipmapImplementationDefault(); + void MAGNUM_LOCAL mipmapImplementationDSA(); + static MAGNUM_LOCAL MipmapImplementation mipmapImplementation; + + typedef void(AbstractTexture::*Image1DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector<1, GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); + void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + static Image1DImplementation image1DImplementation; + + typedef void(AbstractTexture::*Image2DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector2&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); + void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + static Image2DImplementation image2DImplementation; + + typedef void(AbstractTexture::*Image3DImplementation)(GLenum, GLint, InternalFormat, const Math::Vector3&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); + void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + void MAGNUM_LOCAL imageImplementationDSA(GLenum target, GLint mipLevel, InternalFormat internalFormat, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + static Image3DImplementation image3DImplementation; + + typedef void(AbstractTexture::*SubImage1DImplementation)(GLenum, GLint, const Math::Vector<1, GLint>&, const Math::Vector<1, GLsizei>&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); + void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + static SubImage1DImplementation subImage1DImplementation; + + typedef void(AbstractTexture::*SubImage2DImplementation)(GLenum, GLint, const Math::Vector2&, const Math::Vector2&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); + void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector2& offset, const Math::Vector2& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + static SubImage2DImplementation subImage2DImplementation; + + typedef void(AbstractTexture::*SubImage3DImplementation)(GLenum, GLint, const Math::Vector3&, const Math::Vector3&, AbstractImage::Components, AbstractImage::ComponentType, const GLvoid*); + void MAGNUM_LOCAL subImageImplementationDefault(GLenum target, GLint mipLevel, const Math::Vector3& offset, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + void MAGNUM_LOCAL subImageImplementationDSA(GLenum target, GLint mipLevel, const Math::Vector3& offset, const Math::Vector3& size, AbstractImage::Components components, AbstractImage::ComponentType type, const GLvoid* data); + static SubImage3DImplementation subImage3DImplementation; + GLuint _id; }; @@ -715,18 +795,15 @@ template<> struct AbstractTexture::DataHelper<1> { inline constexpr static Target target() { return Target::Texture1D; } inline static void setWrapping(AbstractTexture* texture, const Math::Vector<1, Wrapping>& wrapping) { - texture->bindInternal(); - glTexParameteri(texture->_target, GL_TEXTURE_WRAP_S, static_cast(wrapping[0])); + (texture->*parameteriImplementation)(GL_TEXTURE_WRAP_S, static_cast(wrapping[0])); } template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) { - texture->bindInternal(); - glTexImage1D(target, mipLevel, internalFormat, image->size()[0], 0, static_cast(image->components()), static_cast(image->type()), image->data()); + (texture->*image1DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data()); } template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector<1, GLint>& offset, Image* image) { - texture->bindInternal(); - glTexSubImage1D(target, mipLevel, offset[0], image->size()[0], static_cast(image->components()), static_cast(image->type()), image->data()); + (texture->*subImage1DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data()); } }; #endif @@ -742,21 +819,18 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<2> { inline constexpr static Target target() { return Target::Texture2D; } - static void setWrapping(AbstractTexture* texture, const Math::Vector<2, Wrapping>& wrapping); + static void setWrapping(AbstractTexture* texture, const Math::Vector2& wrapping); template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) { - texture->bindInternal(); - glTexImage2D(target, mipLevel, internalFormat, image->size()[0], image->size()[1], 0, static_cast(image->components()), static_cast(image->type()), image->data()); + (texture->*image2DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data()); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector<2, GLint>& offset, Image* image) { - texture->bindInternal(); - glTexSubImage2D(target, mipLevel, offset[0], offset[1], image->size()[0], image->size()[1], static_cast(image->components()), static_cast(image->type()), image->data()); + template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector2& offset, Image* image) { + (texture->*subImage2DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data()); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector<2, GLint>& offset, Image* image) { - texture->bindInternal(); - glTexSubImage2D(target, mipLevel, offset[0], offset[1], image->size()[0], 1, static_cast(image->components()), static_cast(image->type()), image->data()); + template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector2& offset, Image* image) { + (texture->*subImage2DImplementation)(target, mipLevel, offset, Math::Vector2(image->size(), 1), image->components(), image->type(), image->data()); } }; template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { @@ -767,21 +841,18 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { inline constexpr static Target target() { return Target::Texture3D; } - static void setWrapping(AbstractTexture* texture, const Math::Vector<3, Wrapping>& wrapping); + static void setWrapping(AbstractTexture* texture, const Math::Vector3& wrapping); template inline static typename std::enable_if::type set(AbstractTexture* texture, GLenum target, GLint mipLevel, InternalFormat internalFormat, Image* image) { - texture->bindInternal(); - glTexImage3D(target, mipLevel, internalFormat, image->size()[0], image->size()[1], image->size()[2], 0, static_cast(image->components()), static_cast(image->type()), image->data()); + (texture->*image3DImplementation)(target, mipLevel, internalFormat, image->size(), image->components(), image->type(), image->data()); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector<3, GLint>& offset, Image* image) { - texture->bindInternal(); - glTexSubImage3D(target, mipLevel, offset[0], offset[1], offset[2], image->size()[0], image->size()[1], image->size()[2], static_cast(image->components()), static_cast(image->type()), image->data()); + template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector3& offset, Image* image) { + (texture->*subImage3DImplementation)(target, mipLevel, offset, image->size(), image->components(), image->type(), image->data()); } - template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector<3, GLint>& offset, Image* image) { - texture->bindInternal(); - glTexSubImage3D(target, mipLevel, offset[0], offset[1], offset[2], image->size()[0], image->size()[1], 1, static_cast(image->components()), static_cast(image->type()), image->data()); + template inline static typename std::enable_if::type setSub(AbstractTexture* texture, GLenum target, GLint mipLevel, const Math::Vector3& offset, Image* image) { + (texture->*subImage3DImplementation)(target, mipLevel, offset, Math::Vector3(image->size(), 1), image->components(), image->type(), image->data()); } }; #endif diff --git a/src/BufferedTexture.cpp b/src/BufferedTexture.cpp index ffd5a6d20..aefb40905 100644 --- a/src/BufferedTexture.cpp +++ b/src/BufferedTexture.cpp @@ -15,8 +15,31 @@ #include "BufferedTexture.h" +#include "Buffer.h" +#include "Context.h" +#include "Extensions.h" + namespace Magnum { +BufferedTexture::SetBufferImplementation BufferedTexture::setBufferImplementation = &BufferedTexture::setBufferImplementationDefault; + +void BufferedTexture::initializeContextBasedFunctionality(Context* context) { + if(context->isExtensionSupported()) { + Debug() << "BufferedTexture: using" << Extensions::GL::EXT::direct_state_access::string() << "features"; + + setBufferImplementation = &BufferedTexture::setBufferImplementationDSA; + } +} + +void BufferedTexture::setBufferImplementationDefault(BufferedTexture::InternalFormat internalFormat, Buffer* buffer) { + bindInternal(); + glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, buffer->id()); +} + +void BufferedTexture::setBufferImplementationDSA(BufferedTexture::InternalFormat internalFormat, Buffer* buffer) { + glTextureBufferEXT(id(), GL_TEXTURE_BUFFER, internalFormat, buffer->id()); +} + #ifndef MAGNUM_TARGET_GLES BufferedTexture::InternalFormat::InternalFormat(Components components, ComponentType type) { #define internalFormatSwitch(c) switch(type) { \ diff --git a/src/BufferedTexture.h b/src/BufferedTexture.h index be3e6f8b8..ae483585e 100644 --- a/src/BufferedTexture.h +++ b/src/BufferedTexture.h @@ -20,10 +20,12 @@ */ #include "AbstractTexture.h" -#include "Buffer.h" namespace Magnum { +class Buffer; +class Context; + #ifndef MAGNUM_TARGET_GLES /** @brief Buffered texture @@ -37,10 +39,19 @@ using data setting functions in Buffer itself. When using buffered texture in the shader, use `samplerBuffer` and fetch the data using integer coordinates in `texelFetch()`. +@section BufferedTexture-performance-optimization Performance optimizations +If extension @extension{EXT,direct_state_access} is available, setBuffer() +uses DSA function to avoid unnecessary calls to @fn_gl{ActiveTexture} and +@fn_gl{BindTexture}. See @ref AbstractTexture-performance-optimization +"relevant section in AbstractTexture documentation" and respective function +documentation for more information. + @requires_gl @requires_gl31 Extension @extension{ARB,texture_buffer_object} */ -class BufferedTexture: private AbstractTexture { +class MAGNUM_EXPORT BufferedTexture: private AbstractTexture { + friend class Context; + BufferedTexture(const BufferedTexture& other) = delete; BufferedTexture(BufferedTexture&& other) = delete; BufferedTexture& operator=(const BufferedTexture& other) = delete; @@ -130,12 +141,20 @@ class BufferedTexture: private AbstractTexture { * Binds given buffer to this texture. The buffer itself can be then * filled with data of proper format at any time using Buffer own data * setting functions. - * @see @fn_gl{BindTexture}, @fn_gl{TexBuffer} + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexBuffer} + * or @fn_gl_extension{TextureBuffer,EXT,direct_state_access} */ - void setBuffer(InternalFormat internalFormat, Buffer* buffer) { - bindInternal(); - glTexBuffer(GL_TEXTURE_BUFFER, internalFormat, buffer->id()); + inline void setBuffer(InternalFormat internalFormat, Buffer* buffer) { + (this->*setBufferImplementation)(internalFormat, buffer); } + + private: + static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); + + typedef void(BufferedTexture::*SetBufferImplementation)(InternalFormat, Buffer*); + void MAGNUM_LOCAL setBufferImplementationDefault(InternalFormat internalFormat, Buffer* buffer); + void MAGNUM_LOCAL setBufferImplementationDSA(InternalFormat internalFormat, Buffer* buffer); + static SetBufferImplementation setBufferImplementation; }; /** @relates BufferedTexture diff --git a/src/Context.cpp b/src/Context.cpp index 70c9e391b..eed515804 100644 --- a/src/Context.cpp +++ b/src/Context.cpp @@ -24,6 +24,7 @@ #include "Buffer.h" #include "Extensions.h" #include "Implementation/State.h" +#include "BufferedTexture.h" using namespace std; @@ -201,8 +202,9 @@ Context::Context() { /* Initialize functionality based on current OpenGL version and extensions */ AbstractShaderProgram::initializeContextBasedFunctionality(this); - Buffer::initializeContextBasedFunctionality(this); AbstractTexture::initializeContextBasedFunctionality(this); + Buffer::initializeContextBasedFunctionality(this); + BufferedTexture::initializeContextBasedFunctionality(this); } Context::~Context() { diff --git a/src/CubeMapTexture.h b/src/CubeMapTexture.h index e94df7529..ef5de7806 100644 --- a/src/CubeMapTexture.h +++ b/src/CubeMapTexture.h @@ -27,9 +27,9 @@ namespace Magnum { @brief Cube map texture %Texture used mainly for environemnt maps. See AbstractTexture documentation -for more information about usage. It consists of 6 square textures generating -6 faces of the cube as following. Note that all images must be turned upside -down (+Y is top): +for more information. It consists of 6 square textures generating 6 faces of +the cube as following. Note that all images must be turned upside down (+Y is +top): +----+ | -Y | @@ -105,7 +105,7 @@ class CubeMapTexture: public AbstractTexture { * @param coordinate Coordinate * @return Pointer to self (for method chaining) */ - template inline CubeMapTexture* setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector<2, GLint>& offset, const Image* image) { + template inline CubeMapTexture* setSubData(Coordinate coordinate, GLint mipLevel, const Math::Vector2& offset, const Image* image) { DataHelper<2>::setSub(this, static_cast(coordinate), mipLevel, offset, image); return this; } diff --git a/src/CubeMapTextureArray.h b/src/CubeMapTextureArray.h index 00fb98a04..0af738bef 100644 --- a/src/CubeMapTextureArray.h +++ b/src/CubeMapTextureArray.h @@ -26,7 +26,7 @@ namespace Magnum { /** @brief Cube map texture array -For information about usage, see CubeMapTexture documentation. +For information, see CubeMapTexture and AbstractTexture documentation. When using cube map texture in the shader, use `samplerCubeArray`. Unlike classic textures, coordinates for cube map textures is signed three-part @@ -59,7 +59,7 @@ class CubeMapTextureArray: public AbstractTexture { /** * @copydoc Texture::setWrapping() */ - inline CubeMapTextureArray* setWrapping(const Math::Vector<3, Wrapping>& wrapping) { + inline CubeMapTextureArray* setWrapping(const Math::Vector3& wrapping) { DataHelper<3>::setWrapping(this, wrapping); return this; } @@ -94,8 +94,8 @@ class CubeMapTextureArray: public AbstractTexture { * * @see setSubData(GLsizei, Coordinate, GLint, const Math::Vector<2, GLint>&, const Image*) */ - template inline CubeMapTextureArray* setSubData(GLint mipLevel, const Math::Vector<3, GLint>& offset, const Image* image) { - DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, offset, image, Math::Vector<3, GLsizei>(Math::Vector())); + template inline CubeMapTextureArray* setSubData(GLint mipLevel, const Math::Vector3& offset, const Image* image) { + DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, offset, image, Math::Vector3(Math::Vector())); return this; } @@ -114,8 +114,8 @@ class CubeMapTextureArray: public AbstractTexture { * * @see setSubData(GLint, const Math::Vector<3, GLint>&, const Image*) */ - template inline CubeMapTextureArray* setSubData(GLsizei layer, Coordinate coordinate, GLint mipLevel, const Math::Vector<2, GLint>& offset, const Image* image) { - DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, Math::Vector<3, GLint>(offset, layer*6+static_cast(coordinate)), image, Math::Vector<2, GLsizei>(Math::Vector())); + template inline CubeMapTextureArray* setSubData(GLsizei layer, Coordinate coordinate, GLint mipLevel, const Math::Vector2& offset, const Image* image) { + DataHelper<3>::setSub(this, GL_TEXTURE_CUBE_MAP_ARRAY, mipLevel, Math::Vector3(offset, layer*6+static_cast(coordinate)), image, Math::Vector<2, GLsizei>(Math::Vector())); return this; } }; diff --git a/src/Texture.h b/src/Texture.h index 417b85ec9..dcbc3a190 100644 --- a/src/Texture.h +++ b/src/Texture.h @@ -28,7 +28,7 @@ namespace Magnum { @brief %Texture Template class for one- to three-dimensional textures. See AbstractTexture -documentation for more information about usage. +documentation for more information. In shader, the texture is used via `sampler1D`, `sampler2D` or `sampler3D` depending on dimension count. Note that you can have more than one texture bound @@ -120,12 +120,15 @@ template class Texture: public AbstractTexture { * * Sets wrapping type for coordinates out of range (0, 1) for normal * textures and (0, textureSizeInGivenDirection-1) for rectangle - * textures. + * textures. If @extension{EXT,direct_state_access} is not available, + * the texture is bound to some layer before the operation. * @attention For rectangle textures only some modes are supported, - * see @ref AbstractTexture::Wrapping "Wrapping" documentation for - * more information. - * @see bind(), @fn_gl{TexParameter} with @def_gl{TEXTURE_WRAP_S}, - * @def_gl{TEXTURE_WRAP_T}, @def_gl{TEXTURE_WRAP_R} + * see @ref AbstractTexture::Wrapping "Wrapping" documentation + * for more information. + * @see @fn_gl{ActiveTexture}, @fn_gl{BindTexture} and @fn_gl{TexParameter} + * or @fn_gl_extension{TextureParameter,EXT,direct_state_access} + * with @def_gl{TEXTURE_WRAP_S}, @def_gl{TEXTURE_WRAP_T}, + * @def_gl{TEXTURE_WRAP_R} * @todo Use something better for this than Vector (mainly something * that can easily create all values the same) */ @@ -143,8 +146,13 @@ template class Texture: public AbstractTexture { * @return Pointer to self (for method chaining) * * Sets texture data from given image. The image is not deleted - * afterwards. - * @see bind(), @fn_gl{TexImage1D}, @fn_gl{TexImage2D}, @fn_gl{TexImage3D} + * afterwards. 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{TexImage1D}/ + * @fn_gl{TexImage2D}/@fn_gl{TexImage3D} or + * @fn_gl_extension{TextureImage1D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureImage2D,EXT,direct_state_access}/ + * @fn_gl_extension{TextureImage3D,EXT,direct_state_access} */ template inline Texture* setData(GLint mipLevel, InternalFormat internalFormat, Image* image) { DataHelper::set(this, _target, mipLevel, internalFormat, image); @@ -167,7 +175,14 @@ template class Texture: public AbstractTexture { * taken as if it had the last dimension equal to 1. It can be used * for e.g. updating 3D texture with multiple 2D images or for filling * 1D texture array (which is two-dimensional) with 1D images. - * @see bind(), @fn_gl{TexSubImage1D}, @fn_gl{TexSubImage2D}, @fn_gl{TexSubImage3D} + * + * 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{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} */ template inline Texture* setSubData(GLint mipLevel, const typename DimensionTraits::VectorType& offset, Image* image) { DataHelper::setSub(this, _target, mipLevel, offset, image);