From f746eaaf7dc7191724646344f878314a62a75e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 2 Jan 2016 01:11:06 +0100 Subject: [PATCH] Workaround broken full cube map compressed image query on NVidia. The query returns only data of the first cube map face and not the others, worked around that by querying each face separately. --- src/Magnum/CubeMapTexture.cpp | 29 ++++++++++++++------ src/Magnum/CubeMapTexture.h | 3 ++ src/Magnum/Implementation/TextureState.cpp | 9 ++++++ src/Magnum/Implementation/TextureState.h | 1 + src/Magnum/Implementation/driverSpecific.cpp | 4 +++ 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/Magnum/CubeMapTexture.cpp b/src/Magnum/CubeMapTexture.cpp index e1c7d48b8..f29e4ea51 100644 --- a/src/Magnum/CubeMapTexture.cpp +++ b/src/Magnum/CubeMapTexture.cpp @@ -110,18 +110,19 @@ void CubeMapTexture::compressedImage(const Int level, CompressedImage3D& image) const Vector3i size{imageSize(level), 6}; const GLint textureDataSize = (this->*Context::current()->state().texture->getCubeLevelCompressedImageSizeImplementation)(level); - const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize); + std::size_t dataOffset, dataSize; + std::tie(dataOffset, dataSize) = Implementation::compressedImageDataOffsetSizeFor(image, size, textureDataSize); GLint format; (this->*Context::current()->state().texture->getCubeLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); /* Reallocate only if needed */ Containers::Array data{image.release()}; - if(data.size() < dataSize) - data = Containers::Array{dataSize}; + if(data.size() < dataOffset + dataSize) + data = Containers::Array{dataOffset + dataSize}; Buffer::unbindInternal(Buffer::TargetHint::PixelPack); image.storage().applyPack(); - glGetCompressedTextureImage(_id, level, data.size(), data); + (this->*Context::current()->state().texture->getFullCompressedCubeImageImplementation)(level, size.xy(), dataOffset, dataSize, data); image.setData(image.storage(), CompressedPixelFormat(format), size, std::move(data)); } @@ -135,19 +136,20 @@ void CubeMapTexture::compressedImage(const Int level, CompressedBufferImage3D& i const Vector3i size{imageSize(level), 6}; const GLint textureDataSize = (this->*Context::current()->state().texture->getCubeLevelCompressedImageSizeImplementation)(level); - const std::size_t dataSize = Implementation::compressedImageDataSizeFor(image, size, textureDataSize); + std::size_t dataOffset, dataSize; + std::tie(dataOffset, dataSize) = Implementation::compressedImageDataOffsetSizeFor(image, size, textureDataSize); GLint format; (this->*Context::current()->state().texture->getCubeLevelParameterivImplementation)(level, GL_TEXTURE_INTERNAL_FORMAT, &format); /* Reallocate only if needed */ - if(image.dataSize() < dataSize) - image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataSize}, usage); + if(image.dataSize() < dataOffset + dataSize) + image.setData(image.storage(), CompressedPixelFormat(format), size, {nullptr, dataOffset + dataSize}, usage); else image.setData(image.storage(), CompressedPixelFormat(format), size, nullptr, usage); image.buffer().bindInternal(Buffer::TargetHint::PixelPack); image.storage().applyPack(); - glGetCompressedTextureImage(_id, level, dataSize, nullptr); + (this->*Context::current()->state().texture->getFullCompressedCubeImageImplementation)(level, size.xy(), dataOffset, dataSize, nullptr); } CompressedBufferImage3D CubeMapTexture::compressedImage(const Int level, CompressedBufferImage3D&& image, const BufferUsage usage) { @@ -417,6 +419,17 @@ GLint CubeMapTexture::getLevelCompressedImageSizeImplementationDSAEXTImmutableWo #endif #ifndef MAGNUM_TARGET_GLES +void CubeMapTexture::getCompressedImageImplementationDSA(const GLint level, const Vector2i&, const std::size_t dataOffset, const std::size_t dataSize, GLvoid* const data) { + glGetCompressedTextureImage(_id, level, dataOffset + dataSize, data); +} + +void CubeMapTexture::getCompressedImageImplementationDSASingleSliceWorkaround(const GLint level, const Vector2i& size, const std::size_t dataOffset, const std::size_t dataSize, GLvoid* const data) { + /* On NVidia (358.16) calling glGetCompressedTextureImage() extracts only + the first face */ + for(Int face = 0; face != 6; ++face) + glGetCompressedTextureSubImage(_id, level, 0, 0, face, size.x(), size.y(), 1, dataOffset + dataSize/6, static_cast(data) + dataSize*face/6); +} + void CubeMapTexture::getImageImplementationDefault(const Coordinate coordinate, const GLint level, const Vector2i&, const PixelFormat format, const PixelType type, std::size_t, GLvoid* const data) { bindInternal(); glGetTexImage(GLenum(coordinate), level, GLenum(format), GLenum(type), data); diff --git a/src/Magnum/CubeMapTexture.h b/src/Magnum/CubeMapTexture.h index f49d8966c..98650ab4f 100644 --- a/src/Magnum/CubeMapTexture.h +++ b/src/Magnum/CubeMapTexture.h @@ -962,6 +962,9 @@ class MAGNUM_EXPORT CubeMapTexture: public AbstractTexture { #endif #ifndef MAGNUM_TARGET_GLES + void MAGNUM_LOCAL getCompressedImageImplementationDSA(GLint level, const Vector2i& size, std::size_t dataOffset, std::size_t dataSize, GLvoid* data); + void MAGNUM_LOCAL getCompressedImageImplementationDSASingleSliceWorkaround(GLint level, const Vector2i& size, std::size_t dataOffset, std::size_t dataSize, GLvoid* data); + void MAGNUM_LOCAL getImageImplementationDefault(Coordinate coordinate, GLint level, const Vector2i& size, PixelFormat format, PixelType type, std::size_t dataSize, GLvoid* data); void MAGNUM_LOCAL getImageImplementationDSA(Coordinate coordinate, GLint level, const Vector2i& size, PixelFormat format, PixelType type, std::size_t dataSize, GLvoid* data); void MAGNUM_LOCAL getImageImplementationDSAEXT(Coordinate coordinate, GLint level, const Vector2i& size, PixelFormat format, PixelType type, std::size_t dataSize, GLvoid* data); diff --git a/src/Magnum/Implementation/TextureState.cpp b/src/Magnum/Implementation/TextureState.cpp index 0d0491a55..c3073daa3 100644 --- a/src/Magnum/Implementation/TextureState.cpp +++ b/src/Magnum/Implementation/TextureState.cpp @@ -277,6 +277,15 @@ TextureState::TextureState(Context& context, std::vector& extension getCubeImageImplementation = &CubeMapTexture::getImageImplementationDefault; getCompressedCubeImageImplementation = &CubeMapTexture::getCompressedImageImplementationDefault; } + + /* Full compressed cubemap image query implementation (extensions added + above) */ + if((context.detectedDriver() & Context::DetectedDriver::NVidia) && + context.isExtensionSupported() && + !context.isDriverWorkaroundDisabled("nv-cubemap-broken-full-compressed-image-query")) + getFullCompressedCubeImageImplementation = &CubeMapTexture::getCompressedImageImplementationDSASingleSliceWorkaround; + else + getFullCompressedCubeImageImplementation = &CubeMapTexture::getCompressedImageImplementationDSA; #endif /* Texture storage implementation for desktop and ES */ diff --git a/src/Magnum/Implementation/TextureState.h b/src/Magnum/Implementation/TextureState.h index d7ff7ed15..475c62b27 100644 --- a/src/Magnum/Implementation/TextureState.h +++ b/src/Magnum/Implementation/TextureState.h @@ -103,6 +103,7 @@ struct TextureState { #ifndef MAGNUM_TARGET_GLES GLint(CubeMapTexture::*getCubeLevelCompressedImageSizeImplementation)(GLint); void(CubeMapTexture::*getCubeImageImplementation)(CubeMapTexture::Coordinate, 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)(CubeMapTexture::Coordinate, GLint, const Vector2i&, std::size_t, GLvoid*); #endif void(CubeMapTexture::*cubeSubImageImplementation)(CubeMapTexture::Coordinate, GLint, const Vector2i&, const Vector2i&, PixelFormat, PixelType, const GLvoid*); diff --git a/src/Magnum/Implementation/driverSpecific.cpp b/src/Magnum/Implementation/driverSpecific.cpp index 2ee50b188..a07246c4c 100644 --- a/src/Magnum/Implementation/driverSpecific.cpp +++ b/src/Magnum/Implementation/driverSpecific.cpp @@ -57,6 +57,10 @@ namespace { based on whether I'm querying all faces (ARB_DSA) or a single face (non-DSA, EXT_DSA) */ "nv-cubemap-inconsistent-compressed-image-size", + + /* NVidia drivers (358.16) return only the first slice of compressed + cube map image when querying all six slice using ARB_DSA API */ + "nv-cubemap-broken-full-compressed-image-query", #endif #ifdef CORRADE_TARGET_NACL