diff options
Diffstat (limited to 'src/gui/opengl/qopengltexture.cpp')
-rw-r--r-- | src/gui/opengl/qopengltexture.cpp | 293 |
1 files changed, 240 insertions, 53 deletions
diff --git a/src/gui/opengl/qopengltexture.cpp b/src/gui/opengl/qopengltexture.cpp index c58ddbd71e..6b83c17fd4 100644 --- a/src/gui/opengl/qopengltexture.cpp +++ b/src/gui/opengl/qopengltexture.cpp @@ -97,9 +97,11 @@ QOpenGLTexturePrivate::QOpenGLTexturePrivate(QOpenGLTexture::Target textureTarge break; case QOpenGLTexture::TargetCubeMap: bindingTarget = QOpenGLTexture::BindingTargetCubeMap; + faces = 6; break; case QOpenGLTexture::TargetCubeMapArray: bindingTarget = QOpenGLTexture::BindingTargetCubeMapArray; + faces = 6; break; case QOpenGLTexture::Target2DMultisample: bindingTarget = QOpenGLTexture::BindingTarget2DMultisample; @@ -175,7 +177,7 @@ bool QOpenGLTexturePrivate::create() void QOpenGLTexturePrivate::destroy() { - if (!context) { + if (!textureId) { // not created or already destroyed return; } @@ -401,6 +403,9 @@ static bool isSizedTextureFormat(QOpenGLTexture::TextureFormat internalFormat) case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: return true; + case QOpenGLTexture::RGB8_ETC1: + return false; + case QOpenGLTexture::DepthFormat: case QOpenGLTexture::AlphaFormat: @@ -442,20 +447,23 @@ static bool isTextureTargetMultisample(QOpenGLTexture::Target target) return false; } -void QOpenGLTexturePrivate::allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) +bool QOpenGLTexturePrivate::isUsingImmutableStorage() const { - // Resolve the actual number of mipmap levels we can use - mipLevels = evaluateMipLevels(); - // Use immutable storage whenever possible, falling back to mutable // Note that if multisample textures are not supported at all, we'll still fail into // the mutable storage allocation - const bool useImmutableStorage = isSizedTextureFormat(format) + return isSizedTextureFormat(format) && (isTextureTargetMultisample(target) ? features.testFlag(QOpenGLTexture::ImmutableMultisampleStorage) : features.testFlag(QOpenGLTexture::ImmutableStorage)); +} + +void QOpenGLTexturePrivate::allocateStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) +{ + // Resolve the actual number of mipmap levels we can use + mipLevels = evaluateMipLevels(); - if (useImmutableStorage) + if (isUsingImmutableStorage()) allocateImmutableStorage(); else allocateMutableStorage(pixelFormat, pixelType); @@ -663,6 +671,7 @@ static QOpenGLTexture::PixelFormat pixelFormatCompatibleWithInternalFormat(QOpen case QOpenGLTexture::SRGB_Alpha_DXT3: case QOpenGLTexture::SRGB_Alpha_DXT5: case QOpenGLTexture::SRGB_BP_UNorm: + case QOpenGLTexture::RGB8_ETC1: return QOpenGLTexture::RGBA; case QOpenGLTexture::R11_EAC_UNorm: @@ -840,6 +849,7 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: case QOpenGLTexture::RGBA8_ETC2_EAC: case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: + case QOpenGLTexture::RGB8_ETC1: return QOpenGLTexture::UInt8; case QOpenGLTexture::DepthFormat: @@ -857,8 +867,133 @@ static QOpenGLTexture::PixelType pixelTypeCompatibleWithInternalFormat(QOpenGLTe return QOpenGLTexture::NoPixelType; } +static bool isCompressedFormat(QOpenGLTexture::TextureFormat internalFormat) +{ + switch (internalFormat) { + case QOpenGLTexture::NoFormat: + + 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: + return false; + + 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: + case QOpenGLTexture::R11_EAC_UNorm: + case QOpenGLTexture::R11_EAC_SNorm: + case QOpenGLTexture::RG11_EAC_UNorm: + case QOpenGLTexture::RG11_EAC_SNorm: + case QOpenGLTexture::RGB8_ETC2: + case QOpenGLTexture::SRGB8_ETC2: + case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: + case QOpenGLTexture::RGBA8_ETC2_EAC: + case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: + case QOpenGLTexture::RGB8_ETC1: + 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::allocateMutableStorage(QOpenGLTexture::PixelFormat pixelFormat, QOpenGLTexture::PixelType pixelType) { + // There is no way to allocate mutable storage for compressed textures in in + // versions older than OpenGL 3.1 and OpenGL ES 3.0, because the older specs + // do not mandate accepting null data pointers for glCompressedTexImage*D, + // unlike glTexImage*D (which in turn does not accept compressed formats). + if (isCompressedFormat(format)) { + storageAllocated = true; + return; + } + switch (target) { case QOpenGLTexture::TargetBuffer: // Buffer textures get their storage from an external OpenGL buffer @@ -1196,86 +1331,121 @@ void QOpenGLTexturePrivate::setCompressedData(int mipLevel, int layer, QOpenGLTe int dataSize, const void *data, const QOpenGLPixelTransferOptions * const options) { + if (!isCompressedFormat(format)) { + qWarning("Cannot set compressed data for non-compressed format 0x%x", format); + return; + } + + const bool needsFullSpec = !isUsingImmutableStorage(); // was allocateStorage() a no-op? + switch (target) { case QOpenGLTexture::Target1D: Q_UNUSED(layer); Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage1D(textureId, target, bindingTarget, mipLevel, - 0, mipLevelSize( mipLevel, dimensions[0] ), - format, dataSize, data, options); + if (needsFullSpec) { + texFuncs->glCompressedTextureImage1D(textureId, target, bindingTarget, mipLevel, + format, + mipLevelSize(mipLevel, dimensions[0]), + 0, dataSize, data, options); + } else { + texFuncs->glCompressedTextureSubImage1D(textureId, target, bindingTarget, mipLevel, + 0, mipLevelSize( mipLevel, dimensions[0] ), + format, dataSize, data, options); + } break; case QOpenGLTexture::Target1DArray: Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, - 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - 1, - format, dataSize, data, options); + if (!needsFullSpec) { + texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, + 0, layer, + mipLevelSize(mipLevel, dimensions[0]), + 1, + format, dataSize, data, options); + } break; case QOpenGLTexture::Target2D: Q_UNUSED(layer); Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, - 0, 0, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - format, dataSize, data, options); + if (needsFullSpec) { + texFuncs->glCompressedTextureImage2D(textureId, target, bindingTarget, mipLevel, + format, + mipLevelSize(mipLevel, dimensions[0]), + mipLevelSize(mipLevel, dimensions[1]), + 0, dataSize, data, options); + } else { + texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, mipLevel, + 0, 0, + mipLevelSize(mipLevel, dimensions[0]), + mipLevelSize(mipLevel, dimensions[1]), + format, dataSize, data, options); + } break; case QOpenGLTexture::Target2DArray: Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - 1, - format, dataSize, data, options); + if (!needsFullSpec) { + texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, + 0, 0, layer, + mipLevelSize(mipLevel, dimensions[0]), + mipLevelSize(mipLevel, dimensions[1]), + 1, + format, dataSize, data, options); + } break; case QOpenGLTexture::Target3D: Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layer, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - mipLevelSize(mipLevel, dimensions[2]), - format, dataSize, data, options); + if (needsFullSpec) { + texFuncs->glCompressedTextureImage3D(textureId, target, bindingTarget, mipLevel, + format, + mipLevelSize(mipLevel, dimensions[0]), + mipLevelSize(mipLevel, dimensions[1]), + mipLevelSize(mipLevel, dimensions[2]), + 0, dataSize, data, options); + } else { + texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, + 0, 0, layer, + mipLevelSize(mipLevel, dimensions[0]), + mipLevelSize(mipLevel, dimensions[1]), + mipLevelSize(mipLevel, dimensions[2]), + format, dataSize, data, options); + } break; case QOpenGLTexture::TargetCubeMap: Q_UNUSED(layer); - texFuncs->glCompressedTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel, - 0, 0, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - format, dataSize, data, options); + if (needsFullSpec) { + texFuncs->glCompressedTextureImage2D(textureId, cubeFace, bindingTarget, mipLevel, + format, + mipLevelSize(mipLevel, dimensions[0]), + mipLevelSize(mipLevel, dimensions[1]), + 0, dataSize, data, options); + } else { + texFuncs->glCompressedTextureSubImage2D(textureId, cubeFace, bindingTarget, mipLevel, + 0, 0, + mipLevelSize(mipLevel, dimensions[0]), + mipLevelSize(mipLevel, dimensions[1]), + format, dataSize, data, options); + } break; case QOpenGLTexture::TargetCubeMapArray: { int faceIndex = cubeFace - QOpenGLTexture::CubeMapPositiveX; int layerFace = 6 * layer + faceIndex; - texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, - 0, 0, layerFace, - mipLevelSize(mipLevel, dimensions[0]), - mipLevelSize(mipLevel, dimensions[1]), - 1, - format, dataSize, data, options); + if (!needsFullSpec) { + texFuncs->glCompressedTextureSubImage3D(textureId, target, bindingTarget, mipLevel, + 0, 0, layerFace, + mipLevelSize(mipLevel, dimensions[0]), + mipLevelSize(mipLevel, dimensions[1]), + 1, + format, dataSize, data, options); + } break; } case QOpenGLTexture::TargetRectangle: - Q_UNUSED(mipLevel); - Q_UNUSED(layer); - Q_UNUSED(cubeFace); - texFuncs->glCompressedTextureSubImage2D(textureId, target, bindingTarget, 0, - 0, 0, - dimensions[0], - dimensions[1], - format, dataSize, data, options); - break; - case QOpenGLTexture::Target2DMultisample: case QOpenGLTexture::Target2DMultisampleArray: case QOpenGLTexture::TargetBuffer: @@ -1857,6 +2027,7 @@ QOpenGLTexture *QOpenGLTexturePrivate::createTextureView(QOpenGLTexture::Target \value SRGB8_PunchThrough_Alpha1_ETC2 Equivalent to GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 \value RGBA8_ETC2_EAC Equivalent to GL_COMPRESSED_RGBA8_ETC2_EAC \value SRGB8_Alpha8_ETC2_EAC Equivalent to GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC + \value RGB8_ETC1 Equivalent to GL_ETC1_RGB8_OES \value SRGB8 Equivalent to GL_SRGB8 \value SRGB8_Alpha8 Equivalent to GL_SRGB8_ALPHA8 @@ -2394,6 +2565,7 @@ void QOpenGLTexture::setFormat(TextureFormat format) case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2: case QOpenGLTexture::RGBA8_ETC2_EAC: case QOpenGLTexture::SRGB8_Alpha8_ETC2_EAC: + case QOpenGLTexture::RGB8_ETC1: case RG3B2: case R5G6B5: case RGB5A1: @@ -3464,6 +3636,8 @@ QPair<int, int> QOpenGLTexture::mipLevelRange() const The automatic mipmap generation is enabled by default. + \note Mipmap generation is not supported for compressed textures with OpenGL ES 2.0. + \sa isAutoMipMapGenerationEnabled(), generateMipMaps() */ void QOpenGLTexture::setAutoMipMapGenerationEnabled(bool enabled) @@ -3489,6 +3663,9 @@ bool QOpenGLTexture::isAutoMipMapGenerationEnabled() const have disabled automatic mipmap generation then you need to call this function or the overload to create the mipmap chain. + \note Mipmap generation is not supported for compressed textures with OpenGL + ES 2.0. + \sa setAutoMipMapGenerationEnabled(), setMipLevels(), mipLevels() */ void QOpenGLTexture::generateMipMaps() @@ -3496,6 +3673,11 @@ void QOpenGLTexture::generateMipMaps() Q_D(QOpenGLTexture); Q_ASSERT(d->texFuncs); Q_ASSERT(d->textureId); + if (isCompressedFormat(d->format)) { + if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) + if (ctx->isOpenGLES() && ctx->format().majorVersion() < 3) + return; + } d->texFuncs->glGenerateTextureMipmap(d->textureId, d->target, d->bindingTarget); } @@ -3516,6 +3698,11 @@ void QOpenGLTexture::generateMipMaps(int baseLevel, bool resetBaseLevel) Q_D(QOpenGLTexture); Q_ASSERT(d->texFuncs); Q_ASSERT(d->textureId); + if (isCompressedFormat(d->format)) { + if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) + if (ctx->isOpenGLES() && ctx->format().majorVersion() < 3) + return; + } int oldBaseLevel; if (resetBaseLevel) oldBaseLevel = mipBaseLevel(); |