From 0371ebd9a382860b2b81c4e117fc0709cd9eff61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Fri, 28 Apr 2017 23:38:28 +0200 Subject: [PATCH] SVGA3D: work around broken glTex[ture][Sub]Image*D() for arrays. 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. Relevant commit in the Mesa sources: https://github.com/mesa3d/mesa/commit/2aa9ff0cda1f6ad97c83d5583fab7a84efabe19e This is one of the uglier workarounds -- I had to reintroduce multiple code paths for glTexImage() which were removed when implementing ARB_DSA and the workaround consists of basically a bunch of functions that are slicing the image and calling the original implementations with each slice. --- src/Magnum/AbstractTexture.cpp | 151 ++++++++++++++++--- src/Magnum/AbstractTexture.h | 36 ++++- src/Magnum/CubeMapTexture.cpp | 14 +- src/Magnum/CubeMapTexture.h | 5 + src/Magnum/Implementation/TextureState.cpp | 49 +++++- src/Magnum/Implementation/TextureState.h | 7 +- src/Magnum/Implementation/driverSpecific.cpp | 8 + 7 files changed, 233 insertions(+), 37 deletions(-) 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" }; }