diff options
author | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2014-11-13 11:36:33 +0100 |
---|---|---|
committer | Giuseppe D'Angelo <giuseppe.dangelo@kdab.com> | 2014-11-13 12:45:03 +0100 |
commit | 279317b0673438a3ede3fe38d1c68c7f7ecc5c5f (patch) | |
tree | d981c394e8594a366f317584780d91cd3d45ae15 | |
parent | 10d1b6c7b842c2500f25f21bbff96b6da4caeccb (diff) |
QOpenGLTexture: fix storage allocation
Storage allocation was quite wrong in the general case.
1) We can't pass unsized texture formats to immutable storage
allocations, so we need to check for that.
2) Second, when allocating mutable storage on GLES, apparently
the driver is allowed to peek at the external pixel type. The
texture can then only get data in the pixel type passed
at storage allocation time.
(I guess that, for the sake of simplicity, the drivers are allowed
not to perform any pixel conversions.)
I'm still not convinced about the wording in the GLES2/3
specifications, but apparently ANGLE behaves this way, so we need
to fix this kind of allocation. Unfortunately the only way
is to ask, at storage allocation time, what's the external
pixel format/type, so we need to introduce an allocateStorage
overload taking those as arguments and using them for the
glTexImage* calls.
Task-number: QTBUG-41822
Task-number: QTBUG-42623
Change-Id: Idf745d549f01c5db3e56e86cf9b1f53a77cfccc6
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
-rw-r--r-- | src/gui/opengl/qopengltexture.cpp | 166 | ||||
-rw-r--r-- | src/gui/opengl/qopengltexture.h | 1 | ||||
-rw-r--r-- | src/gui/opengl/qopengltexture_p.h | 4 |
3 files changed, 159 insertions, 12 deletions
diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index 9c30efe148..6f0eb17397 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -294,16 +294,124 @@ int QOpenGLTexturePrivate::evaluateMipLevels() const } } -void QOpenGLTexturePrivate::allocateStorage() +static bool isSizedTextureFormat(QOpenGLTexture::TextureFormat internalFormat) +{ + switch (internalFormat) { + case QOpenGLTexture::NoFormat: + return false; + + case QOpenGLTexture::R8_UNorm: + case QOpenGLTexture::RG8_UNorm: + case QOpenGLTexture::RGB8_UNorm: + case QOpenGLTexture::RGBA8_UNorm: + case QOpenGLTexture::R16_UNorm: + case QOpenGLTexture::RG16_UNorm: + case QOpenGLTexture::RGB16_UNorm: + case QOpenGLTexture::RGBA16_UNorm: + case QOpenGLTexture::R8_SNorm: + case QOpenGLTexture::RG8_SNorm: + case QOpenGLTexture::RGB8_SNorm: + case QOpenGLTexture::RGBA8_SNorm: + case QOpenGLTexture::R16_SNorm: + case QOpenGLTexture::RG16_SNorm: + case QOpenGLTexture::RGB16_SNorm: + case QOpenGLTexture::RGBA16_SNorm: + case QOpenGLTexture::R8U: + case QOpenGLTexture::RG8U: + case QOpenGLTexture::RGB8U: + case QOpenGLTexture::RGBA8U: + case QOpenGLTexture::R16U: + case QOpenGLTexture::RG16U: + case QOpenGLTexture::RGB16U: + case QOpenGLTexture::RGBA16U: + case QOpenGLTexture::R32U: + case QOpenGLTexture::RG32U: + case QOpenGLTexture::RGB32U: + case QOpenGLTexture::RGBA32U: + case QOpenGLTexture::R8I: + case QOpenGLTexture::RG8I: + case QOpenGLTexture::RGB8I: + case QOpenGLTexture::RGBA8I: + case QOpenGLTexture::R16I: + case QOpenGLTexture::RG16I: + case QOpenGLTexture::RGB16I: + case QOpenGLTexture::RGBA16I: + case QOpenGLTexture::R32I: + case QOpenGLTexture::RG32I: + case QOpenGLTexture::RGB32I: + case QOpenGLTexture::RGBA32I: + case QOpenGLTexture::R16F: + case QOpenGLTexture::RG16F: + case QOpenGLTexture::RGB16F: + case QOpenGLTexture::RGBA16F: + case QOpenGLTexture::R32F: + case QOpenGLTexture::RG32F: + case QOpenGLTexture::RGB32F: + case QOpenGLTexture::RGBA32F: + case QOpenGLTexture::RGB9E5: + case QOpenGLTexture::RG11B10F: + case QOpenGLTexture::RG3B2: + case QOpenGLTexture::R5G6B5: + case QOpenGLTexture::RGB5A1: + case QOpenGLTexture::RGBA4: + case QOpenGLTexture::RGB10A2: + + case QOpenGLTexture::D16: + case QOpenGLTexture::D24: + case QOpenGLTexture::D32: + case QOpenGLTexture::D32F: + + case QOpenGLTexture::D24S8: + case QOpenGLTexture::D32FS8X24: + + case QOpenGLTexture::S8: + + case QOpenGLTexture::RGB_DXT1: + case QOpenGLTexture::RGBA_DXT1: + case QOpenGLTexture::RGBA_DXT3: + case QOpenGLTexture::RGBA_DXT5: + case QOpenGLTexture::R_ATI1N_UNorm: + case QOpenGLTexture::R_ATI1N_SNorm: + case QOpenGLTexture::RG_ATI2N_UNorm: + case QOpenGLTexture::RG_ATI2N_SNorm: + case QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT: + case QOpenGLTexture::RGB_BP_SIGNED_FLOAT: + case QOpenGLTexture::RGB_BP_UNorm: + case QOpenGLTexture::SRGB8: + case QOpenGLTexture::SRGB8_Alpha8: + case QOpenGLTexture::SRGB_DXT1: + case QOpenGLTexture::SRGB_Alpha_DXT1: + case QOpenGLTexture::SRGB_Alpha_DXT3: + case QOpenGLTexture::SRGB_Alpha_DXT5: + case QOpenGLTexture::SRGB_BP_UNorm: + return true; + + case QOpenGLTexture::DepthFormat: + case QOpenGLTexture::AlphaFormat: + + case QOpenGLTexture::RGBFormat: + case QOpenGLTexture::RGBAFormat: + + case QOpenGLTexture::LuminanceFormat: + + case QOpenGLTexture::LuminanceAlphaFormat: + return false; + } + + Q_UNREACHABLE(); + return false; +} + +void QOpenGLTexturePrivate::allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) { // Resolve the actual number of mipmap levels we can use mipLevels = evaluateMipLevels(); - // Use immutable storage whenever possible, falling back to mutable when not available - if (features.testFlag(QOpenGLTexture::ImmutableStorage)) + // Use immutable storage whenever possible, falling back to mutable + if (features.testFlag(QOpenGLTexture::ImmutableStorage) && isSizedTextureFormat(format)) allocateImmutableStorage(); else - allocateMutableStorage(); + allocateMutableStorage(pixelFormat, pixelType); } static QOpenGLTexture::PixelFormat pixelFormatCompatibleWithInternalFormat(QOpenGLTexture::TextureFormat internalFormat) @@ -534,11 +642,8 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe return QOpenGLTexture::NoPixelType; } -void QOpenGLTexturePrivate::allocateMutableStorage() +void QOpenGLTexturePrivate::allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) { - const QOpenGLTexture::PixelFormat pixelFormat = pixelFormatCompatibleWithInternalFormat(format); - const QOpenGLTexture::PixelType pixelType = pixelTypeCompatibleWithInternalFormat(format); - switch (target) { case QOpenGLTexture::TargetBuffer: // Buffer textures get their storage from an external OpenGL buffer @@ -2436,17 +2541,58 @@ bool QOpenGLTexture::isFixedSamplePositions() const Once storage has been allocated for the texture then pixel data can be uploaded via one of the setData() overloads. + \note If immutable texture storage is not available, + then a default pixel format and pixel type will be used to + create the mutable storage. You can use the other + allocateStorage() overload to specify exactly the pixel format + and the pixel type to use when allocating mutable storage; + this is particulary useful under certain OpenGL ES implementations + (notably, OpenGL ES 2), where the pixel format and the pixel type + used at allocation time must perfectly match the format + and the type passed to any subsequent setData() call. + \sa isStorageAllocated(), setData() */ void QOpenGLTexture::allocateStorage() { Q_D(QOpenGLTexture); if (d->create()) { - d->allocateStorage(); + const QOpenGLTexture::PixelFormat pixelFormat = pixelFormatCompatibleWithInternalFormat(d->format); + const QOpenGLTexture::PixelType pixelType = pixelTypeCompatibleWithInternalFormat(d->format); + d->allocateStorage(pixelFormat, pixelType); } } /*! + \since 5.5 + + Allocates server-side storage for this texture object taking + into account, the format, dimensions, mipmap levels, array + layers and cubemap faces. + + Once storage has been allocated it is no longer possible to change + these properties. + + If supported QOpenGLTexture makes use of immutable texture + storage. However, if immutable texture storage is not available, + then the specified \a pixelFormat and \a pixelType will be used + to allocate mutable storage; note that in certain OpenGL implementations + (notably, OpenGL ES 2) they must perfectly match the format + and the type passed to any subsequent setData() call. + + Once storage has been allocated for the texture then pixel data + can be uploaded via one of the setData() overloads. + + \sa isStorageAllocated(), setData() +*/ +void QOpenGLTexture::allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) +{ + Q_D(QOpenGLTexture); + if (d->create()) + d->allocateStorage(pixelFormat, pixelType); +} + +/*! Returns \c true if server-side storage for this texture as been allocated. @@ -2670,7 +2816,7 @@ void QOpenGLTexture::setData(const QImage& image, MipMapGeneration genMipMaps) setSize(image.width(), image.height()); setMipLevels(genMipMaps == GenerateMipMaps ? maximumMipLevels() : 1); - allocateStorage(); + allocateStorage(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); // Upload pixel data and generate mipmaps QImage glImage = image.convertToFormat(QImage::Format_RGBA8888); diff --git a/src/gui/opengl/qopengltexture.h b/src/gui/opengl/qopengltexture.h index 9fee298b90..578f3389a3 100644 --- a/src/gui/opengl/qopengltexture.h +++ b/src/gui/opengl/qopengltexture.h @@ -361,6 +361,7 @@ public: void setFixedSamplePositions(bool fixed); bool isFixedSamplePositions() const; void allocateStorage(); + void allocateStorage(PixelFormat pixelFormat, PixelType pixelType); bool isStorageAllocated() const; QOpenGLTexture *createTextureView(Target target, diff --git a/src/gui/opengl/qopengltexture_p.h b/src/gui/opengl/qopengltexture_p.h index b584d3ec8f..3b70010231 100644 --- a/src/gui/opengl/qopengltexture_p.h +++ b/src/gui/opengl/qopengltexture_p.h @@ -87,8 +87,8 @@ public: bool isBound() const; bool isBound(uint unit) const; - void allocateStorage(); - void allocateMutableStorage(); + void allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType); + void allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType); void allocateImmutableStorage(); void setData(int mipLevel, int layer, QOpenGLTexture::CubeMapFace cubeFace, QOpenGLTexture::PixelFormat sourceFormat, QOpenGLTexture::PixelType sourceType, |