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