diff --git a/src/Magnum/AbstractTexture.cpp b/src/Magnum/AbstractTexture.cpp index a63d2ba05..19a3daeb0 100644 --- a/src/Magnum/AbstractTexture.cpp +++ b/src/Magnum/AbstractTexture.cpp @@ -1471,18 +1471,57 @@ void AbstractTexture::compressedSubImageImplementationDSAEXT(const GLint level, } #endif -void AbstractTexture::subImageImplementationDefault(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data) { +void AbstractTexture::imageImplementationDefault(const GLenum target, const GLint level, const TextureFormat internalFormat, const Vector2i& size, const PixelFormat format, const PixelType type, const GLvoid* const data, const PixelStorage&) { + bindInternal(); + glTexImage2D(target, level, GLint(internalFormat), size.x(), size.y(), 0, GLenum(format), GLenum(type), data); +} + +#ifndef MAGNUM_TARGET_GLES +void AbstractTexture::imageImplementationSvga3DSliceBySlice(const GLenum target, const GLint level, const TextureFormat internalFormat, const Vector2i& size, const PixelFormat format, const PixelType type, const GLvoid* const data, const PixelStorage& storage) { + /* Allocate and upload the first slice */ + imageImplementationDefault(target, level, internalFormat, size, format, type, data, storage); + + /* Upload the next slices slice by slice only if this is an array texture + with more than one slice and we are copying from user memory (not from a + buffer). The hard work is done by the subImage() implementation. + Moreover, I am simply calling the default implementation and not the DSA + one as just using glTexImage() pollutes the state already anyway so the + DSA cleanness is not worth it. */ + /** @todo this will break when we support uploading from buffer offset (i.e. data != nullptr) */ + if(target == GL_TEXTURE_1D_ARRAY && data && size.y() > 1) + subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage2DImplementationDefault>(level, {0, 1}, {size.x(), size.y() - 1}, format, type, static_cast(data) + std::get<1>(storage.dataProperties(format, type, {size, 1})).x(), storage); +} +#endif + +void AbstractTexture::subImage2DImplementationDefault(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&) { bindInternal(); glTexSubImage2D(_target, level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), GLenum(type), data); } +#ifndef MAGNUM_TARGET_GLES +template void AbstractTexture::subImageImplementationSvga3DSliceBySlice(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* const data, const PixelStorage& storage) { + /* Upload the data slice by slice only if this is an array texture and we + are copying from user memory (not from a buffer) */ + if(_target == GL_TEXTURE_1D_ARRAY && data) { + const std::size_t stride = std::get<1>(storage.dataProperties(format, type, {size, 1})).x(); + for(Int i = 0; i != size.y(); ++i) + (this->*original)(level, {offset.x(), offset.y() + i}, {size.x(), 1}, format, type, static_cast(data) + stride*i, storage); + + /* Otherwise just pass-though to the default implementation */ + } else (this->*original)(level, offset, size, format, type, data, storage); +} + +template void AbstractTexture::subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage2DImplementationDefault>(GLint, const Vector2i&, const Vector2i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); +template void AbstractTexture::subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage2DImplementationDSA>(GLint, const Vector2i&, const Vector2i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); +#endif + void AbstractTexture::compressedSubImageImplementationDefault(const GLint level, const Vector2i& offset, const Vector2i& size, const CompressedPixelFormat format, const GLvoid* const data, const GLsizei dataSize) { bindInternal(); glCompressedTexSubImage2D(_target, level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), dataSize, data); } #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::subImageImplementationDSA(const GLint level, const Vector2i& offset, const Vector2i& size, const PixelFormat format, const PixelType type, const GLvoid* const data) { +void AbstractTexture::subImage2DImplementationDSA(const GLint level, const Vector2i& offset, const Vector2i& size, const PixelFormat format, const PixelType type, const GLvoid* const data, const PixelStorage&) { glTextureSubImage2D(_id, level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), GLenum(type), data); } @@ -1490,7 +1529,7 @@ void AbstractTexture::compressedSubImageImplementationDSA(const GLint level, con glCompressedTextureSubImage2D(_id, level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), dataSize, data); } -void AbstractTexture::subImageImplementationDSAEXT(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDSAEXT(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&) { _flags |= ObjectFlag::Created; glTextureSubImage2DEXT(_id, _target, level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), GLenum(type), data); } @@ -1502,7 +1541,52 @@ void AbstractTexture::compressedSubImageImplementationDSAEXT(GLint level, const #endif #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) -void AbstractTexture::subImageImplementationDefault(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data) { +void AbstractTexture::imageImplementationDefault(GLint level, TextureFormat internalFormat, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&) { + bindInternal(); + #ifndef CORRADE_TARGET_NACL + #ifndef MAGNUM_TARGET_GLES2 + glTexImage3D + #else + glTexImage3DOES + #endif + (_target, level, GLint(internalFormat), size.x(), size.y(), size.z(), 0, GLenum(format), GLenum(type), data); + #else + static_cast(level); + static_cast(internalFormat); + static_cast(size); + static_cast(format); + static_cast(type); + static_cast(data); + CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + #endif +} + +#ifndef MAGNUM_TARGET_WEBGL +void AbstractTexture::imageImplementationSvga3DSliceBySlice(GLint level, TextureFormat internalFormat, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage& storage) { + /* Allocate and upload the first slice */ + imageImplementationDefault(level, internalFormat, size, format, type, data, storage); + + /* Upload the next slices slice by slice only if this is an array texture + with more than one slice or a 3D texture and we are copying from user + memory (not from a buffer). The hard work is done by the subImage() + implementation. Moreover, I am simply calling the default implementation + and not the DSA one as just using glTexImage() pollutes the state + already anyway so the DSA cleanness is not worth it. */ + /** @todo this will break when we support uploading from buffer offset (i.e. data != nullptr) */ + if(( + #ifndef MAGNUM_TARGET_GLES2 + _target == GL_TEXTURE_2D_ARRAY || _target == GL_TEXTURE_3D + #else + _target == GL_TEXTURE_3D_OES + #endif + ) && data && size.z() > 1) + { + subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage3DImplementationDefault>(level, {0, 0, 1}, {size.xy(), size.z() - 1}, format, type, static_cast(data) + std::get<1>(storage.dataProperties(format, type, size)).xy().product(), storage); + } +} +#endif + +void AbstractTexture::subImage3DImplementationDefault(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&) { bindInternal(); #ifndef MAGNUM_TARGET_GLES2 glTexSubImage3D(_target, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), GLenum(format), GLenum(type), data); @@ -1519,6 +1603,32 @@ void AbstractTexture::subImageImplementationDefault(GLint level, const Vector3i& #endif } +#ifndef MAGNUM_TARGET_WEBGL +template void AbstractTexture::subImageImplementationSvga3DSliceBySlice(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage& storage) { + /* Upload the data slice by slice only if this is an array texture and we + are copying from user memory (not from a buffer) */ + if( + #ifndef MAGNUM_TARGET_GLES2 + _target == GL_TEXTURE_2D_ARRAY || _target == GL_TEXTURE_3D + #else + _target == GL_TEXTURE_3D_OES + #endif + ) + { + const std::size_t stride = std::get<1>(storage.dataProperties(format, type, size)).xy().product(); + for(Int i = 0; i != size.z(); ++i) + (this->*original)(level, {offset.xy(), offset.z() + i}, {size.xy(), 1}, format, type, static_cast(data) + stride*i, storage); + + /* Otherwise just pass-though to the default implementation */ + } else (this->*original)(level, offset, size, format, type, data, storage); +} + +template void AbstractTexture::subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage3DImplementationDefault>(GLint, const Vector3i&, const Vector3i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); +#ifndef MAGNUM_TARGET_GLES +template void AbstractTexture::subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage3DImplementationDSA>(GLint, const Vector3i&, const Vector3i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); +#endif +#endif + void AbstractTexture::compressedSubImageImplementationDefault(const GLint level, const Vector3i& offset, const Vector3i& size, const CompressedPixelFormat format, const GLvoid* const data, const GLsizei dataSize) { bindInternal(); #ifndef MAGNUM_TARGET_GLES2 @@ -1537,7 +1647,7 @@ void AbstractTexture::compressedSubImageImplementationDefault(const GLint level, #endif #ifndef MAGNUM_TARGET_GLES -void AbstractTexture::subImageImplementationDSA(const GLint level, const Vector3i& offset, const Vector3i& size, const PixelFormat format, const PixelType type, const GLvoid* const data) { +void AbstractTexture::subImage3DImplementationDSA(const GLint level, const Vector3i& offset, const Vector3i& size, const PixelFormat format, const PixelType type, const GLvoid* const data, const PixelStorage&) { glTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), GLenum(format), GLenum(type), data); } @@ -1545,7 +1655,7 @@ void AbstractTexture::compressedSubImageImplementationDSA(const GLint level, con glCompressedTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), GLenum(format), dataSize, data); } -void AbstractTexture::subImageImplementationDSAEXT(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data) { +void AbstractTexture::subImageImplementationDSAEXT(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&) { _flags |= ObjectFlag::Created; glTextureSubImage3DEXT(_id, _target, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), GLenum(format), GLenum(type), data); } @@ -1935,12 +2045,11 @@ void AbstractTexture::DataHelper<2>::setImage(AbstractTexture& texture, const GL Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif image.storage().applyUnpack(); - texture.bindInternal(); - glTexImage2D(target, level, GLint(internalFormat), image.size().x(), image.size().y(), 0, GLenum(image.format()), GLenum(image.type()), image.data() + (texture.*Context::current().state().texture->image2DImplementation)(target, level, internalFormat, image.size(), image.format(), image.type(), image.data() #ifdef MAGNUM_TARGET_GLES2 + Implementation::pixelStorageSkipOffset(image) #endif - ); + , image.storage()); } void AbstractTexture::DataHelper<2>::setCompressedImage(AbstractTexture& texture, const GLenum target, const GLint level, const CompressedImageView2D& image) { @@ -1985,7 +2094,7 @@ void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const #ifdef MAGNUM_TARGET_GLES2 + Implementation::pixelStorageSkipOffset(image) #endif - ); + , image.storage()); } void AbstractTexture::DataHelper<2>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Vector2i& offset, const CompressedImageView2D& image) { @@ -2004,7 +2113,7 @@ void AbstractTexture::DataHelper<2>::setCompressedSubImage(AbstractTexture& text void AbstractTexture::DataHelper<2>::setSubImage(AbstractTexture& texture, const GLint level, const Vector2i& offset, BufferImage2D& image) { image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); image.storage().applyUnpack(); - (texture.*Context::current().state().texture->subImage2DImplementation)(level, offset, image.size(), image.format(), image.type(), nullptr); + (texture.*Context::current().state().texture->subImage2DImplementation)(level, offset, image.size(), image.format(), image.type(), nullptr, image.storage()); } void AbstractTexture::DataHelper<2>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Vector2i& offset, CompressedBufferImage2D& image) { @@ -2024,17 +2133,11 @@ void AbstractTexture::DataHelper<3>::setImage(AbstractTexture& texture, const GL Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); #endif image.storage().applyUnpack(); - texture.bindInternal(); - #ifndef MAGNUM_TARGET_GLES2 - glTexImage3D(texture._target, level, GLint(internalFormat), image.size().x(), image.size().y(), image.size().z(), 0, GLenum(image.format()), GLenum(image.type()), image.data()); - #elif !defined(CORRADE_TARGET_NACL) - glTexImage3DOES(texture._target, level, GLint(internalFormat), image.size().x(), image.size().y(), image.size().z(), 0, GLenum(image.format()), GLenum(image.type()), image.data() + Implementation::pixelStorageSkipOffset(image)); - #else - static_cast(level); - static_cast(internalFormat); - static_cast(image); - CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ - #endif + (texture.*Context::current().state().texture->image3DImplementation)(level, internalFormat, image.size(), image.format(), image.type(), image.data() + #ifdef MAGNUM_TARGET_GLES2 + + Implementation::pixelStorageSkipOffset(image) + #endif + , image.storage()); } void AbstractTexture::DataHelper<3>::setCompressedImage(AbstractTexture& texture, const GLint level, const CompressedImageView3D& image) { @@ -2089,7 +2192,7 @@ void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const #ifdef MAGNUM_TARGET_GLES2 + Implementation::pixelStorageSkipOffset(image) #endif - ); + , image.storage()); } void AbstractTexture::DataHelper<3>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Vector3i& offset, const CompressedImageView3D& image) { @@ -2109,7 +2212,7 @@ void AbstractTexture::DataHelper<3>::setCompressedSubImage(AbstractTexture& text void AbstractTexture::DataHelper<3>::setSubImage(AbstractTexture& texture, const GLint level, const Vector3i& offset, BufferImage3D& image) { image.buffer().bindInternal(Buffer::TargetHint::PixelUnpack); image.storage().applyUnpack(); - (texture.*Context::current().state().texture->subImage3DImplementation)(level, offset, image.size(), image.format(), image.type(), nullptr); + (texture.*Context::current().state().texture->subImage3DImplementation)(level, offset, image.size(), image.format(), image.type(), nullptr, image.storage()); } void AbstractTexture::DataHelper<3>::setCompressedSubImage(AbstractTexture& texture, const GLint level, const Vector3i& offset, CompressedBufferImage3D& image) { diff --git a/src/Magnum/AbstractTexture.h b/src/Magnum/AbstractTexture.h index 9112c7bb2..7b9aada83 100644 --- a/src/Magnum/AbstractTexture.h +++ b/src/Magnum/AbstractTexture.h @@ -632,22 +632,46 @@ class MAGNUM_EXPORT AbstractTexture: public AbstractObject { void MAGNUM_LOCAL compressedSubImageImplementationDSAEXT(GLint level, const Math::Vector<1, GLint>& offset, const Math::Vector<1, GLsizei>& size, CompressedPixelFormat format, const GLvoid* data, GLsizei dataSize); #endif - void MAGNUM_LOCAL subImageImplementationDefault(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data); + void MAGNUM_LOCAL imageImplementationDefault(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL imageImplementationSvga3DSliceBySlice(GLenum target, GLint level, TextureFormat internalFormat, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #endif + /* Had to put explicit "2D" in the name so it's not overloaded and + Clang is able to pass it as template parameter to + subImageImplementationSvga3DSliceBySlice(). GCC had no problem with + the original. */ + void MAGNUM_LOCAL subImage2DImplementationDefault(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #ifndef MAGNUM_TARGET_GLES + template void MAGNUM_LOCAL subImageImplementationSvga3DSliceBySlice(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage& storage); + #endif void MAGNUM_LOCAL compressedSubImageImplementationDefault(GLint level, const Vector2i& offset, const Vector2i& size, CompressedPixelFormat format, const GLvoid* data, GLsizei dataSize); #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL subImageImplementationDSA(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data); - void MAGNUM_LOCAL subImageImplementationDSAEXT(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data); + void MAGNUM_LOCAL subImage2DImplementationDSA(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + void MAGNUM_LOCAL subImageImplementationDSAEXT(GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); void MAGNUM_LOCAL compressedSubImageImplementationDSA(GLint level, const Vector2i& offset, const Vector2i& size, CompressedPixelFormat format, const GLvoid* data, GLsizei dataSize); void MAGNUM_LOCAL compressedSubImageImplementationDSAEXT(GLint level, const Vector2i& offset, const Vector2i& size, CompressedPixelFormat format, const GLvoid* data, GLsizei dataSize); #endif #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - void MAGNUM_LOCAL subImageImplementationDefault(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data); + void MAGNUM_LOCAL imageImplementationDefault(GLint level, TextureFormat internalFormat, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #ifndef MAGNUM_TARGET_WEBGL + void MAGNUM_LOCAL imageImplementationSvga3DSliceBySlice(GLint level, TextureFormat internalFormat, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #endif + /* Had to put explicit "3D" in the name so it's not overloaded and + Clang is able to pass it as template parameter to + subImageImplementationSvga3DSliceBySlice(). GCC had no problem with + the original. */ + void MAGNUM_LOCAL subImage3DImplementationDefault(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #ifndef MAGNUM_TARGET_WEBGL + template void MAGNUM_LOCAL subImageImplementationSvga3DSliceBySlice(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage& storage); + #endif void MAGNUM_LOCAL compressedSubImageImplementationDefault(GLint level, const Vector3i& offset, const Vector3i& size, CompressedPixelFormat format, const GLvoid* data, GLsizei dataSize); #endif #ifndef MAGNUM_TARGET_GLES - void MAGNUM_LOCAL subImageImplementationDSA(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data); - void MAGNUM_LOCAL subImageImplementationDSAEXT(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data); + void MAGNUM_LOCAL subImage3DImplementationDSA(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #ifndef MAGNUM_TARGET_WEBGL + void MAGNUM_LOCAL subImageImplementationDSAEXT(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #endif void MAGNUM_LOCAL compressedSubImageImplementationDSA(GLint level, const Vector3i& offset, const Vector3i& size, CompressedPixelFormat format, const GLvoid* data, GLsizei dataSize); void MAGNUM_LOCAL compressedSubImageImplementationDSAEXT(GLint level, const Vector3i& offset, const Vector3i& size, CompressedPixelFormat format, const GLvoid* data, GLsizei dataSize); #endif diff --git a/src/Magnum/CubeMapTexture.cpp b/src/Magnum/CubeMapTexture.cpp index 351ecbe72..865271981 100644 --- a/src/Magnum/CubeMapTexture.cpp +++ b/src/Magnum/CubeMapTexture.cpp @@ -298,7 +298,7 @@ CubeMapTexture& CubeMapTexture::setSubImage(const Int level, const Vector3i& off Buffer::unbindInternal(Buffer::TargetHint::PixelUnpack); image.storage().applyUnpack(); - glTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), image.size().x(), image.size().y(), image.size().z(), GLenum(image.format()), GLenum(image.type()), image.data()); + (this->*Context::current().state().texture->cubeSubImage3DImplementation)(level, offset, image.size(), image.format(), image.type(), image.data(), image.storage()); return *this; } @@ -503,6 +503,18 @@ void CubeMapTexture::getCompressedImageImplementationRobustness(const CubeMapCoo } #endif +#ifndef MAGNUM_TARGET_GLES +void CubeMapTexture::subImageImplementationDefault(const GLint level, const Vector3i& offset, const Vector3i& size, const PixelFormat format, const PixelType type, const GLvoid* const data, const PixelStorage&) { + glTextureSubImage3D(_id, level, offset.x(), offset.y(), offset.z(), size.x(), size.y(), size.z(), GLenum(format), GLenum(type), data); +} + +void CubeMapTexture::subImageImplementationSvga3DSliceBySlice(const GLint level, const Vector3i& offset, const Vector3i& size, const PixelFormat format, const PixelType type, const GLvoid* const data, const PixelStorage& storage) { + const std::size_t stride = std::get<1>(storage.dataProperties(format, type, size)).xy().product(); + for(Int i = 0; i != size.z(); ++i) + subImageImplementationDefault(level, {offset.xy(), offset.z() + i}, {size.xy(), 1}, format, type, static_cast(data) + stride*i, storage); +} +#endif + void CubeMapTexture::subImageImplementationDefault(const CubeMapCoordinate coordinate, const GLint level, const Vector2i& offset, const Vector2i& size, const PixelFormat format, const PixelType type, const GLvoid* const data) { bindInternal(); glTexSubImage2D(GLenum(coordinate), level, offset.x(), offset.y(), size.x(), size.y(), GLenum(format), GLenum(type), data); diff --git a/src/Magnum/CubeMapTexture.h b/src/Magnum/CubeMapTexture.h index 112e09e4c..159844c5a 100644 --- a/src/Magnum/CubeMapTexture.h +++ b/src/Magnum/CubeMapTexture.h @@ -1120,6 +1120,11 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture { void MAGNUM_LOCAL getCompressedImageImplementationRobustness(CubeMapCoordinate coordinate, GLint level, const Vector2i& size, std::size_t dataSize, GLvoid* data); #endif + void MAGNUM_LOCAL subImageImplementationDefault(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #ifndef MAGNUM_TARGET_WEBGL + void MAGNUM_LOCAL subImageImplementationSvga3DSliceBySlice(GLint level, const Vector3i& offset, const Vector3i& size, PixelFormat format, PixelType type, const GLvoid* data, const PixelStorage&); + #endif + void MAGNUM_LOCAL subImageImplementationDefault(CubeMapCoordinate coordinate, GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data); #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL subImageImplementationDSA(CubeMapCoordinate coordinate, GLint level, const Vector2i& offset, const Vector2i& size, PixelFormat format, PixelType type, const GLvoid* data); diff --git a/src/Magnum/Implementation/TextureState.cpp b/src/Magnum/Implementation/TextureState.cpp index b2ed13642..320197d20 100644 --- a/src/Magnum/Implementation/TextureState.cpp +++ b/src/Magnum/Implementation/TextureState.cpp @@ -127,8 +127,8 @@ TextureState::TextureState(Context& context, std::vector& extension getLevelParameterivImplementation = &AbstractTexture::getLevelParameterImplementationDSA; mipmapImplementation = &AbstractTexture::mipmapImplementationDSA; subImage1DImplementation = &AbstractTexture::subImageImplementationDSA; - subImage2DImplementation = &AbstractTexture::subImageImplementationDSA; - subImage3DImplementation = &AbstractTexture::subImageImplementationDSA; + subImage2DImplementation = &AbstractTexture::subImage2DImplementationDSA; + subImage3DImplementation = &AbstractTexture::subImage3DImplementationDSA; compressedSubImage1DImplementation = &AbstractTexture::compressedSubImageImplementationDSA; compressedSubImage2DImplementation = &AbstractTexture::compressedSubImageImplementationDSA; compressedSubImage3DImplementation = &AbstractTexture::compressedSubImageImplementationDSA; @@ -186,10 +186,10 @@ TextureState::TextureState(Context& context, std::vector& extension subImage1DImplementation = &AbstractTexture::subImageImplementationDefault; compressedSubImage1DImplementation = &AbstractTexture::compressedSubImageImplementationDefault; #endif - subImage2DImplementation = &AbstractTexture::subImageImplementationDefault; + subImage2DImplementation = &AbstractTexture::subImage2DImplementationDefault; compressedSubImage2DImplementation = &AbstractTexture::compressedSubImageImplementationDefault; #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - subImage3DImplementation = &AbstractTexture::subImageImplementationDefault; + subImage3DImplementation = &AbstractTexture::subImage3DImplementationDefault; compressedSubImage3DImplementation = &AbstractTexture::compressedSubImageImplementationDefault; #endif @@ -384,6 +384,47 @@ TextureState::TextureState(Context& context, std::vector& extension compressedBlockDataSizeImplementation = &AbstractTexture::compressedBlockDataSizeImplementationDefault; #endif + #ifndef MAGNUM_TARGET_WEBGL + /* SVGA3D workaround for array / 3D / cube map texture upload. Overrides + the DSA / non-DSA function pointers set above. */ + if((context.detectedDriver() & Context::DetectedDriver::Svga3D) && + !context.isDriverWorkaroundDisabled("svga3d-texture-upload-slice-by-slice")) { + #ifndef MAGNUM_TARGET_GLES + image2DImplementation = &AbstractTexture::imageImplementationSvga3DSliceBySlice; + #endif + image3DImplementation = &AbstractTexture::imageImplementationSvga3DSliceBySlice; + #ifndef MAGNUM_TARGET_GLES + if(context.isExtensionSupported()) { + #ifndef MAGNUM_TARGET_GLES + subImage2DImplementation = &AbstractTexture::subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage2DImplementationDSA>; + #endif + subImage3DImplementation = &AbstractTexture::subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage3DImplementationDSA>; + cubeSubImage3DImplementation = &CubeMapTexture::subImageImplementationSvga3DSliceBySlice; + } else + #endif + { + #ifndef MAGNUM_TARGET_GLES + subImage2DImplementation = &AbstractTexture::subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage2DImplementationDefault>; + #endif + subImage3DImplementation = &AbstractTexture::subImageImplementationSvga3DSliceBySlice<&AbstractTexture::subImage3DImplementationDefault>; + #ifndef MAGNUM_TARGET_GLES + cubeSubImage3DImplementation = nullptr; + #endif + } + } else + #endif + { + /* These need to be set up in any case */ + image2DImplementation = &AbstractTexture::imageImplementationDefault; + #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) + image3DImplementation = &AbstractTexture::imageImplementationDefault; + #endif + /* The other subImage implementations were set already above */ + #ifndef MAGNUM_TARGET_GLES + cubeSubImage3DImplementation = &CubeMapTexture::subImageImplementationDefault; + #endif + } + /* Allocate texture bindings array to hold all possible texture units */ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &maxTextureUnits); CORRADE_INTERNAL_ASSERT(maxTextureUnits > 0); diff --git a/src/Magnum/Implementation/TextureState.h b/src/Magnum/Implementation/TextureState.h index b1ba8ceea..7db459334 100644 --- a/src/Magnum/Implementation/TextureState.h +++ b/src/Magnum/Implementation/TextureState.h @@ -91,10 +91,12 @@ struct TextureState { void(AbstractTexture::*subImage1DImplementation)(GLint, const Math::Vector<1, GLint>&, const Math::Vector<1, GLsizei>&, PixelFormat, PixelType, const GLvoid*); void(AbstractTexture::*compressedSubImage1DImplementation)(GLint, const Math::Vector<1, GLint>&, const Math::Vector<1, GLsizei>&, CompressedPixelFormat, const GLvoid*, GLsizei); #endif - void(AbstractTexture::*subImage2DImplementation)(GLint, const Vector2i&, const Vector2i&, PixelFormat, PixelType, const GLvoid*); + void (AbstractTexture::*image2DImplementation)(GLenum, GLint, TextureFormat, const Vector2i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); + void(AbstractTexture::*subImage2DImplementation)(GLint, const Vector2i&, const Vector2i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); void(AbstractTexture::*compressedSubImage2DImplementation)(GLint, const Vector2i&, const Vector2i&, CompressedPixelFormat, const GLvoid*, GLsizei); #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) - void(AbstractTexture::*subImage3DImplementation)(GLint, const Vector3i&, const Vector3i&, PixelFormat, PixelType, const GLvoid*); + void (AbstractTexture::*image3DImplementation)(GLint, TextureFormat, const Vector3i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); + void(AbstractTexture::*subImage3DImplementation)(GLint, const Vector3i&, const Vector3i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); void(AbstractTexture::*compressedSubImage3DImplementation)(GLint, const Vector3i&, const Vector3i&, CompressedPixelFormat, const GLvoid*, GLsizei); #endif void(AbstractTexture::*invalidateImageImplementation)(GLint); @@ -113,6 +115,7 @@ struct TextureState { void(CubeMapTexture::*getCubeImageImplementation)(CubeMapCoordinate, GLint, const Vector2i&, PixelFormat, PixelType, std::size_t, GLvoid*); void(CubeMapTexture::*getFullCompressedCubeImageImplementation)(GLint, const Vector2i&, std::size_t, std::size_t, GLvoid*); void(CubeMapTexture::*getCompressedCubeImageImplementation)(CubeMapCoordinate, GLint, const Vector2i&, std::size_t, GLvoid*); + void(CubeMapTexture::*cubeSubImage3DImplementation)(GLint, const Vector3i&, const Vector3i&, PixelFormat, PixelType, const GLvoid*, const PixelStorage&); #endif void(CubeMapTexture::*cubeSubImageImplementation)(CubeMapCoordinate, GLint, const Vector2i&, const Vector2i&, PixelFormat, PixelType, const GLvoid*); void(CubeMapTexture::*cubeCompressedSubImageImplementation)(CubeMapCoordinate, GLint, const Vector2i&, const Vector2i&, CompressedPixelFormat, const GLvoid*, GLsizei); diff --git a/src/Magnum/Implementation/driverSpecific.cpp b/src/Magnum/Implementation/driverSpecific.cpp index cfbf8d041..53d8d4428 100644 --- a/src/Magnum/Implementation/driverSpecific.cpp +++ b/src/Magnum/Implementation/driverSpecific.cpp @@ -103,6 +103,14 @@ namespace { whole ARB_get_texture_sub_image is disabled. */ "svga3d-gettexsubimage-oob-write", #endif + + /* SVGA3D has broken handling of glTex[ture][Sub]Image*D() for 1D + arrays, 2D arrays, 3D textures and cube map textures where it + uploads just the first slice in the last dimension. This is only + with copies from host memory, not with buffer images. Seems to be + fixed in Mesa 13, but I have no such system to verify that on. + https://github.com/mesa3d/mesa/commit/2aa9ff0cda1f6ad97c83d5583fab7a84efabe19e */ + "svga3d-texture-upload-slice-by-slice" }; }