diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index e92479bb4d..64d1d5a017 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -1496,9 +1496,6 @@ QRhiTextureRenderTargetDescription::QRhiTextureRenderTargetDescription(const QRh the size of the source image() must match the subresource. When providing raw data instead, sufficient number of bytes must be provided in data(). - \note With compressed textures the first upload must always match the - subresource size due to graphics API limitations with some backends. - sourceTopLeft() is supported only for QImage-based uploads, and specifies the top-left corner of the source rectangle. @@ -2197,6 +2194,9 @@ QRhiResource::Type QRhiRenderBuffer::resourceType() const \value UsedWithLoadStore The texture is going to be used with image load/store operations, for example, in a compute shader. + + \value UsedAsCompressedAtlas The texture has a compressed format and the + dimensions of subresource uploads may not match the texture size. */ /*! diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 71064cfc6a..12a294e8c2 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -727,7 +727,8 @@ public: sRGB = 1 << 4, UsedAsTransferSource = 1 << 5, UsedWithGenerateMips = 1 << 6, - UsedWithLoadStore = 1 << 7 + UsedWithLoadStore = 1 << 7, + UsedAsCompressedAtlas = 1 << 8 }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index 373b66df89..d39892ac00 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -1505,9 +1505,29 @@ void QRhiGles2::enqueueSubresUpload(QGles2Texture *texD, QGles2CommandBuffer *cb cmd.args.subImage.data = cbD->retainImage(img); cbD->commands.append(cmd); } else if (!rawData.isEmpty() && isCompressed) { + if (!texD->compressedAtlasBuilt && (texD->flags() & QRhiTexture::UsedAsCompressedAtlas)) { + // Build on first upload since glCompressedTexImage2D cannot take nullptr data + quint32 byteSize = 0; + compressedFormatInfo(texD->m_format, texD->m_pixelSize, nullptr, &byteSize, nullptr); + QByteArray zeroBuf(byteSize, 0); + QGles2CommandBuffer::Command cmd; + cmd.cmd = QGles2CommandBuffer::Command::CompressedImage; + cmd.args.compressedImage.target = texD->target; + cmd.args.compressedImage.texture = texD->texture; + cmd.args.compressedImage.faceTarget = faceTargetBase + uint(layer); + cmd.args.compressedImage.level = level; + cmd.args.compressedImage.glintformat = texD->glintformat; + cmd.args.compressedImage.w = texD->m_pixelSize.width(); + cmd.args.compressedImage.h = texD->m_pixelSize.height(); + cmd.args.compressedImage.size = byteSize; + cmd.args.compressedImage.data = cbD->retainData(zeroBuf); + cbD->commands.append(cmd); + texD->compressedAtlasBuilt = true; + } + const QSize size = subresDesc.sourceSize().isEmpty() ? q->sizeForMipLevel(level, texD->m_pixelSize) : subresDesc.sourceSize(); - if (texD->specified) { + if (texD->specified || texD->compressedAtlasBuilt) { QGles2CommandBuffer::Command cmd; cmd.cmd = QGles2CommandBuffer::Command::CompressedSubImage; cmd.args.compressedSubImage.target = texD->target; @@ -3666,6 +3686,7 @@ void QGles2Texture::release() texture = 0; specified = false; + compressedAtlasBuilt = false; QRHI_RES_RHI(QRhiGles2); if (owns) @@ -3785,6 +3806,7 @@ bool QGles2Texture::buildFrom(QRhiTexture::NativeTexture src) texture = textureId; specified = true; + compressedAtlasBuilt = true; QRHI_RES_RHI(QRhiGles2); QRHI_PROF; diff --git a/src/gui/rhi/qrhigles2_p_p.h b/src/gui/rhi/qrhigles2_p_p.h index e326b661d9..4f64c6d0a3 100644 --- a/src/gui/rhi/qrhigles2_p_p.h +++ b/src/gui/rhi/qrhigles2_p_p.h @@ -148,6 +148,7 @@ struct QGles2Texture : public QRhiTexture GLenum gltype; QGles2SamplerData samplerState; bool specified = false; + bool compressedAtlasBuilt = false; int mipLevelCount = 0; enum Access {