diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index 9d78a49ff..d5f1e7256 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -172,8 +172,9 @@ void AbstractTexture::bindImplementationMulti(const GLint firstTextureUnit, std: /* 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; + for(AbstractTexture* const texture: textures) { + if(texture) texture->createIfNotAlready(); + textureState->bindings[firstTextureUnit + i].second = ids[i] = texture ? texture->_id : 0; ++i; } @@ -181,7 +182,7 @@ void AbstractTexture::bindImplementationMulti(const GLint firstTextureUnit, std: } #endif -AbstractTexture::AbstractTexture(GLenum target): _target(target) { +AbstractTexture::AbstractTexture(GLenum target): _target{target}, _created{false} { glGenTextures(1, &_id); CORRADE_INTERNAL_ASSERT(_id != Implementation::State::DisengagedBinding); } @@ -197,11 +198,25 @@ AbstractTexture::~AbstractTexture() { glDeleteTextures(1, &_id); } -std::string AbstractTexture::label() const { +inline void AbstractTexture::createIfNotAlready() { + if(_created) return; + + /* glGen*() does not create the object, just reserves the name. Some + commands (such as glBindTextures() or glObjectLabel()) operate with IDs + directly and they require the object to be created. Binding the texture + to desired target finally creates it. Also all EXT DSA functions + implicitly create it. */ + bindInternal(); + CORRADE_INTERNAL_ASSERT(_created); +} + +std::string AbstractTexture::label() { + createIfNotAlready(); return Context::current()->state().debug->getLabelImplementation(GL_TEXTURE, _id); } AbstractTexture& AbstractTexture::setLabelInternal(const Containers::ArrayReference label) { + createIfNotAlready(); Context::current()->state().debug->labelImplementation(GL_TEXTURE, _id, label); return *this; } @@ -224,15 +239,19 @@ void AbstractTexture::bindImplementationDefault(GLint textureUnit) { if(textureState->currentTextureUnit != textureUnit) glActiveTexture(GL_TEXTURE0 + (textureState->currentTextureUnit = textureUnit)); + /* Binding the texture finally creates it */ + _created = true; glBindTexture(_target, _id); } #ifndef MAGNUM_TARGET_GLES void AbstractTexture::bindImplementationMulti(GLint textureUnit) { + createIfNotAlready(); glBindTextures(textureUnit, 1, &_id); } void AbstractTexture::bindImplementationDSA(GLint textureUnit) { + _created = true; glBindMultiTextureEXT(GL_TEXTURE0 + textureUnit, _target, _id); } #endif @@ -359,6 +378,7 @@ void AbstractTexture::mipmapImplementationDefault() { #ifndef MAGNUM_TARGET_GLES void AbstractTexture::mipmapImplementationDSA() { + _created = true; glGenerateTextureMipmapEXT(_id, _target); } #endif @@ -383,6 +403,9 @@ void AbstractTexture::bindInternal() { /* Bind the texture to internal unit if not already, update state tracker */ if(textureState->bindings[internalTextureUnit].second == _id) return; textureState->bindings[internalTextureUnit] = {_target, _id}; + + /* Binding the texture finally creates it */ + _created = true; glBindTexture(_target, _id); } @@ -764,6 +787,7 @@ void AbstractTexture::parameterImplementationDefault(GLenum parameter, GLint val #ifndef MAGNUM_TARGET_GLES void AbstractTexture::parameterImplementationDSA(GLenum parameter, GLint value) { + _created = true; glTextureParameteriEXT(_id, _target, parameter, value); } #endif @@ -775,6 +799,7 @@ void AbstractTexture::parameterImplementationDefault(GLenum parameter, GLfloat v #ifndef MAGNUM_TARGET_GLES void AbstractTexture::parameterImplementationDSA(GLenum parameter, GLfloat value) { + _created = true; glTextureParameterfEXT(_id, _target, parameter, value); } #endif @@ -787,6 +812,7 @@ void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLi #ifndef MAGNUM_TARGET_GLES void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLint* values) { + _created = true; glTextureParameterivEXT(_id, _target, parameter, values); } #endif @@ -799,6 +825,7 @@ void AbstractTexture::parameterImplementationDefault(GLenum parameter, const GLf #ifndef MAGNUM_TARGET_GLES void AbstractTexture::parameterImplementationDSA(GLenum parameter, const GLfloat* values) { + _created = true; glTextureParameterfvEXT(_id, _target, parameter, values); } #endif @@ -810,6 +837,7 @@ void AbstractTexture::parameterIImplementationDefault(GLenum parameter, const GL } void AbstractTexture::parameterIImplementationDSA(GLenum parameter, const GLuint* values) { + _created = true; glTextureParameterIuivEXT(_id, _target, parameter, values); } @@ -819,6 +847,7 @@ void AbstractTexture::parameterIImplementationDefault(GLenum parameter, const GL } void AbstractTexture::parameterIImplementationDSA(GLenum parameter, const GLint* values) { + _created = true; glTextureParameterIivEXT(_id, _target, parameter, values); } #endif @@ -837,6 +866,7 @@ void AbstractTexture::getLevelParameterImplementationDefault(GLenum target, GLin #ifndef MAGNUM_TARGET_GLES void AbstractTexture::getLevelParameterImplementationDSA(GLenum target, GLint level, GLenum parameter, GLint* values) { + _created = true; glGetTextureLevelParameterivEXT(_id, target, level, parameter, values); } #endif @@ -860,6 +890,7 @@ void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels } void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size) { + _created = true; glTextureStorage1DEXT(_id, target, levels, GLenum(internalFormat), size[0]); } #endif @@ -920,6 +951,7 @@ void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels #ifndef MAGNUM_TARGET_GLES void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector2i& size) { + _created = true; glTextureStorage2DEXT(_id, target, levels, GLenum(internalFormat), size.x(), size.y()); } #endif @@ -974,6 +1006,7 @@ void AbstractTexture::storageImplementationDefault(GLenum target, GLsizei levels #ifndef MAGNUM_TARGET_GLES void AbstractTexture::storageImplementationDSA(GLenum target, GLsizei levels, TextureFormat internalFormat, const Vector3i& size) { + _created = true; glTextureStorage3DEXT(_id, target, levels, GLenum(internalFormat), size.x(), size.y(), size.z()); } #endif @@ -994,6 +1027,7 @@ void AbstractTexture::storageMultisampleImplementationDefault(const GLenum targe #ifndef MAGNUM_TARGET_GLES void AbstractTexture::storageMultisampleImplementationDSA(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector2i& size, const GLboolean fixedSampleLocations) { + _created = true; glTextureStorage2DMultisampleEXT(_id, target, samples, GLenum(internalFormat), size.x(), size.y(), fixedSampleLocations); } @@ -1008,6 +1042,7 @@ void AbstractTexture::storageMultisampleImplementationDefault(const GLenum targe } void AbstractTexture::storageMultisampleImplementationDSA(const GLenum target, const GLsizei samples, const TextureFormat internalFormat, const Vector3i& size, const GLboolean fixedSampleLocations) { + _created = true; glTextureStorage3DMultisampleEXT(_id, target, samples, GLenum(internalFormat), size.x(), size.y(), size.z(), fixedSampleLocations); } #endif @@ -1019,6 +1054,7 @@ void AbstractTexture::getImageImplementationDefault(const GLenum target, const G } void AbstractTexture::getImageImplementationDSA(const GLenum target, const GLint level, const ColorFormat format, const ColorType type, const std::size_t, GLvoid* const data) { + _created = true; glGetTextureImageEXT(_id, target, level, GLenum(format), GLenum(type), data); } @@ -1035,6 +1071,7 @@ void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, Tex } void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Math::Vector<1, GLsizei>& size, ColorFormat format, ColorType type, const GLvoid* data) { + _created = true; glTextureImage1DEXT(_id, target, level, GLint(internalFormat), size[0], 0, GLenum(format), GLenum(type), data); } #endif @@ -1046,6 +1083,7 @@ void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, Tex #ifndef MAGNUM_TARGET_GLES void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, ColorFormat format, ColorType type, const GLvoid* data) { + _created = true; glTextureImage2DEXT(_id, target, level, GLint(internalFormat), size.x(), size.y(), 0, GLenum(format), GLenum(type), data); } #endif @@ -1070,6 +1108,7 @@ void AbstractTexture::imageImplementationDefault(GLenum target, GLint level, Tex #ifndef MAGNUM_TARGET_GLES void AbstractTexture::imageImplementationDSA(GLenum target, GLint level, TextureFormat internalFormat, const Vector3i& size, ColorFormat format, ColorType type, const GLvoid* data) { + _created = true; glTextureImage3DEXT(_id, target, level, GLint(internalFormat), size.x(), size.y(), size.z(), 0, GLenum(format), GLenum(type), data); } #endif @@ -1081,6 +1120,7 @@ void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, } void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, ColorFormat format, ColorType type, const GLvoid* data) { + _created = true; glTextureSubImage1DEXT(_id, target, level, offset[0], size[0], GLenum(format), GLenum(type), data); } #endif @@ -1092,6 +1132,7 @@ void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, #ifndef MAGNUM_TARGET_GLES void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector2i& offset, const Vector2i& size, ColorFormat format, ColorType type, const GLvoid* data) { + _created = true; glTextureSubImage2DEXT(_id, target, level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), GLenum(type), data); } #endif @@ -1116,6 +1157,7 @@ void AbstractTexture::subImageImplementationDefault(GLenum target, GLint level, #ifndef MAGNUM_TARGET_GLES void AbstractTexture::subImageImplementationDSA(GLenum target, GLint level, const Vector3i& offset, const Vector3i& size, ColorFormat format, ColorType type, const GLvoid* data) { + _created = true; glTextureSubImage3DEXT(_id, target, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), GLenum(format), GLenum(type), data); } #endif @@ -1124,6 +1166,7 @@ void AbstractTexture::invalidateImageImplementationNoOp(GLint) {} #ifndef MAGNUM_TARGET_GLES void AbstractTexture::invalidateImageImplementationARB(GLint level) { + createIfNotAlready(); glInvalidateTexImage(_id, level); } #endif @@ -1132,6 +1175,7 @@ void AbstractTexture::invalidateSubImageImplementationNoOp(GLint, const Vector3i #ifndef MAGNUM_TARGET_GLES void AbstractTexture::invalidateSubImageImplementationARB(GLint level, const Vector3i& offset, const Vector3i& size) { + createIfNotAlready(); glInvalidateTexSubImage(_id, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z()); } #endif diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index edc1f0816..2cdf30902 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -247,7 +247,7 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { * @fn_gl_extension2{GetObjectLabel,EXT,debug_label} with * @def_gl{TEXTURE} */ - std::string label() const; + std::string label(); /** * @brief Set texture label @@ -360,6 +360,8 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { static void MAGNUM_LOCAL bindImplementationMulti(GLint firstTextureUnit, std::initializer_list textures); #endif + void MAGNUM_LOCAL createIfNotAlready(); + void MAGNUM_LOCAL bindImplementationDefault(GLint textureUnit); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL bindImplementationMulti(GLint textureUnit); @@ -484,6 +486,7 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { ColorType MAGNUM_LOCAL imageTypeForInternalFormat(TextureFormat internalFormat); GLuint _id; + bool _created; /* see createIfNotAlready() for details */ }; #ifndef DOXYGEN_GENERATING_OUTPUT @@ -587,13 +590,14 @@ template<> struct MAGNUM_EXPORT AbstractTexture::DataHelper<3> { }; #endif -inline AbstractTexture::AbstractTexture(AbstractTexture&& other) noexcept: _target(other._target), _id(other._id) { +inline AbstractTexture::AbstractTexture(AbstractTexture&& other) noexcept: _target{other._target}, _id{other._id}, _created{other._created} { other._id = 0; } inline AbstractTexture& AbstractTexture::operator=(AbstractTexture&& other) noexcept { std::swap(_target, other._target); std::swap(_id, other._id); + std::swap(_created, other._created); return *this; } diff --git a/src/Magnum/Test/AbstractTextureGLTest.cpp b/src/Magnum/Test/AbstractTextureGLTest.cpp index e5e6f39fe..9fd259e07 100644 --- a/src/Magnum/Test/AbstractTextureGLTest.cpp +++ b/src/Magnum/Test/AbstractTextureGLTest.cpp @@ -93,20 +93,15 @@ void AbstractTextureGLTest::label() { !Context::current()->isExtensionSupported()) CORRADE_SKIP("Required extension is not available"); - { - /** @todo Is this even legal optimization? */ - CORRADE_EXPECT_FAIL("The object must be used at least once before setting/querying label."); - CORRADE_VERIFY(false); - } Texture2D texture; - texture.setMinificationFilter(Sampler::Filter::Linear); CORRADE_COMPARE(texture.label(), ""); + MAGNUM_VERIFY_NO_ERROR(); texture.setLabel("MyTexture"); - CORRADE_COMPARE(texture.label(), "MyTexture"); - MAGNUM_VERIFY_NO_ERROR(); + + CORRADE_COMPARE(texture.label(), "MyTexture"); } }} diff --git a/src/Magnum/Test/BufferTextureGLTest.cpp b/src/Magnum/Test/BufferTextureGLTest.cpp index 0789b2aaa..b67180ea9 100644 --- a/src/Magnum/Test/BufferTextureGLTest.cpp +++ b/src/Magnum/Test/BufferTextureGLTest.cpp @@ -67,19 +67,6 @@ void BufferTextureGLTest::bind() { CORRADE_SKIP(Extensions::GL::ARB::texture_buffer_object::string() + std::string(" is not supported.")); BufferTexture texture; - - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it"); - Buffer buffer; - constexpr UnsignedByte data[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f - }; - buffer.setData(data, BufferUsage::StaticDraw); - texture.setBuffer(BufferTextureFormat::R8UI, buffer); - CORRADE_VERIFY(false); - } - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); diff --git a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp index 253c56ae2..908ae7cc9 100644 --- a/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureArrayGLTest.cpp @@ -103,15 +103,6 @@ void CubeMapTextureArrayGLTest::bind() { CORRADE_SKIP(Extensions::GL::ARB::texture_cube_map_array::string() + std::string(" is not supported.")); CubeMapTextureArray texture; - - #ifndef MAGNUM_TARGET_GLES - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setBaseLevel(0); - CORRADE_VERIFY(false); - } - #endif - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); diff --git a/src/Magnum/Test/CubeMapTextureGLTest.cpp b/src/Magnum/Test/CubeMapTextureGLTest.cpp index 5a7a23805..d93507960 100644 --- a/src/Magnum/Test/CubeMapTextureGLTest.cpp +++ b/src/Magnum/Test/CubeMapTextureGLTest.cpp @@ -128,15 +128,6 @@ void CubeMapTextureGLTest::construct() { void CubeMapTextureGLTest::bind() { CubeMapTexture texture; - - #ifndef MAGNUM_TARGET_GLES - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setBaseLevel(0); - CORRADE_VERIFY(false); - } - #endif - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); diff --git a/src/Magnum/Test/MultisampleTextureGLTest.cpp b/src/Magnum/Test/MultisampleTextureGLTest.cpp index e38fc50c3..0ccde3e5e 100644 --- a/src/Magnum/Test/MultisampleTextureGLTest.cpp +++ b/src/Magnum/Test/MultisampleTextureGLTest.cpp @@ -135,15 +135,6 @@ void MultisampleTextureGLTest::bind2D() { #endif MultisampleTexture2D texture; - - #ifndef MAGNUM_TARGET_GLES - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setStorage(4, TextureFormat::RGBA8, {16, 16}); - CORRADE_VERIFY(false); - } - #endif - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); @@ -163,13 +154,6 @@ void MultisampleTextureGLTest::bind2DArray() { CORRADE_SKIP(Extensions::GL::ARB::texture_multisample::string() + std::string(" is not supported.")); MultisampleTexture2DArray texture; - - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setStorage(4, TextureFormat::RGBA8, {16, 16, 5}); - CORRADE_VERIFY(false); - } - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); diff --git a/src/Magnum/Test/RectangleTextureGLTest.cpp b/src/Magnum/Test/RectangleTextureGLTest.cpp index 8bc4a3994..0bc52e25a 100644 --- a/src/Magnum/Test/RectangleTextureGLTest.cpp +++ b/src/Magnum/Test/RectangleTextureGLTest.cpp @@ -101,15 +101,6 @@ void RectangleTextureGLTest::bind() { CORRADE_SKIP(Extensions::GL::ARB::texture_rectangle::string() + std::string(" is not supported.")); RectangleTexture texture; - - #ifndef MAGNUM_TARGET_GLES - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setWrapping(Sampler::Wrapping::ClampToEdge); - CORRADE_VERIFY(false); - } - #endif - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); diff --git a/src/Magnum/Test/TextureArrayGLTest.cpp b/src/Magnum/Test/TextureArrayGLTest.cpp index 3c0dec591..775bfcc91 100644 --- a/src/Magnum/Test/TextureArrayGLTest.cpp +++ b/src/Magnum/Test/TextureArrayGLTest.cpp @@ -233,13 +233,6 @@ void TextureArrayGLTest::bind1D() { CORRADE_SKIP(Extensions::GL::EXT::texture_array::string() + std::string(" is not supported.")); Texture1DArray texture; - - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setBaseLevel(0); - CORRADE_VERIFY(false); - } - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); @@ -261,15 +254,6 @@ void TextureArrayGLTest::bind2D() { #endif Texture2DArray texture; - - #ifndef MAGNUM_TARGET_GLES - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setBaseLevel(0); - CORRADE_VERIFY(false); - } - #endif - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); diff --git a/src/Magnum/Test/TextureGLTest.cpp b/src/Magnum/Test/TextureGLTest.cpp index 04a786e11..7fe72cfb5 100644 --- a/src/Magnum/Test/TextureGLTest.cpp +++ b/src/Magnum/Test/TextureGLTest.cpp @@ -292,13 +292,6 @@ void TextureGLTest::construct3D() { #ifndef MAGNUM_TARGET_GLES void TextureGLTest::bind1D() { Texture1D texture; - - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setBaseLevel(0); - CORRADE_VERIFY(false); - } - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); @@ -315,15 +308,6 @@ void TextureGLTest::bind1D() { void TextureGLTest::bind2D() { Texture2D texture; - - #ifndef MAGNUM_TARGET_GLES - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setBaseLevel(0); - CORRADE_VERIFY(false); - } - #endif - texture.bind(15); MAGNUM_VERIFY_NO_ERROR(); @@ -344,15 +328,6 @@ void TextureGLTest::bind3D() { #endif Texture3D texture; - - #ifndef MAGNUM_TARGET_GLES - if(Context::current()->isExtensionSupported()) { - CORRADE_EXPECT_FAIL("With ARB_multi_bind the texture must be associated with given target at least once before binding it."); - texture.setBaseLevel(0); - CORRADE_VERIFY(false); - } - #endif - texture.bind(15); MAGNUM_VERIFY_NO_ERROR();